This commit is contained in:
msyu
2025-08-17 22:23:10 +03:00
parent 45c8017ebd
commit 89017a2e92
85 changed files with 2753 additions and 698 deletions
+155
View File
@@ -0,0 +1,155 @@
<cfsilent>
<cfimport prefix="m" taglib="lib"/>
<cfimport prefix="c" taglib="lib/controls"/>
<cfimport prefix="d" taglib="lib/data"/>
<cfimport prefix="layout" taglib="layout"/>
</cfsilent><m:silent silent="No">
<cffunction name="plain2HtmClean">
<cfargument name="s" type="string"/>
<cfreturn request.plain2htm(request.cleanHtm(s))/>
</cffunction>
<cffunction name="cleanInput">
<cfargument name="s" type="string"/>
<cfreturn htmlEditFormat(s)/>
</cffunction>
<m:prepare_detail entity="contract" accessObject="" key="contract_uid" pageInfoOut="pageInfo"/>
<d:bean readonly=true table="elma.aggrements" datasource="#request.DS#" output="d" status="status">
<d:param field="__id" type="uuid" key/>
<d:param field="__name" type="varchar" size="255" preprocessor=#cleanInput# forNull=""/>
<d:param field="company_uid" type="uuid"/>
<d:param field="date_of_aggrement" type="timestamp"/>
<d:param field="date_end_aggrement" type="timestamp"/>
</d:bean>
<m:dispatch_detail
usePRG="No"<!---*** --->
pageInfo=#pageInfo#
id="#d.__id#"
status=#pageInfo.status#
trackOut="tr"
idAttributesOut="id"
/>
<!--- decoration --->
<cfquery name="qDecoration" datasource="#request.DS#">
select
__name as contragent
from elma.companies k
where k.__id=<cfqueryparam cfsqltype="cf_sql_other" value=#d.company_uid#/>
</cfquery>
</m:silent><!---
------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------
---><layout:page section="header" pageInfo=#pageInfo#>
<layout:attribute name="title">
<cfoutput>
Договор
<cfif len(d.__id)>
<b>#d.__name#</b>
[#d.__id#]
</cfif>
</cfoutput>
</layout:attribute>
</layout:page>
<!--- <cfif status.errorState GT 0>
<cfoutput><div class="err">#status.errorMessage#</div></cfoutput>
</cfif>
--->
<cfoutput>
<input type="hidden" name="__id" value="#d.__id#"/>
<input type="hidden" name="track" value="#tr.self#"/>
<input type="hidden" name="pass" value=""/><!--- pass marker to prevent save on submit --->
<div class="detail">
<div class="tr">
<div class="th">__id</div>
<div class="td">#d.__id#</div>
</div>
<div class="tr">
<div class="th">Номер договора</div>
<div class="td">#d.__name#</div>
</div>
<div class="tr">
<div class="th">Контрагент</div>
<div class="td">#qDecoration.contragent# [#d.company_uid#]</div>
</div>
<div class="tr">
<div class="th">Дата договора</div>
<div class="td">#d.date_of_aggrement#</div>
</div>
<div class="tr">
<div class="th">Дата окончания договора</div>
<div class="td">#d.date_end_aggrement#</div>
</div>
</div>
</cfoutput>
<!---
<layout:page section="extension" closeForm="Yes"/>
<cfif d.contragent_id GT 0>
<cfquery name="qContract">
select
d.contract_id
,d.contract
,d.dt_contract
,(select count(*) from specification s where s.contract_id=d.contract_id) as spec_cnt
from contract d
where d.contragent_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#d.contragent_id#"/>
order by 1
</cfquery>
<cfoutput>
<h4>Договоры (#qContract.recordCount#)</h4>
</cfoutput>
<table class="worktable">
<thead>
<tr>
<th><c:link_add canWrite=#pageInfo.writePermitted()# entity="contract" id="#contragent_id#" extra="contragent_id=#d.contragent_id#" fwx=#tr.fwx#/></th>
<th>Номер договора</th>
<th>Дата договора</th>
<th>Спецификаций</th>
<th></th>
</tr>
</thead>
<cfoutput query="qContract">
<tr>
<td>
<c:link_view_edit canWrite=#pageInfo.writePermitted()# entity="contract" id=#contract_id# fwx=#tr.fwx#/>
</td>
<td>#contract#</td>
<td class="c">
#dateFormat(dt_contract,'YYYY-MM-DD')#
</td>
<td class="c">
<cfif spec_cnt GT 0>#spec_cnt#</cfif>
</td>
<td class="c">
<c:link_del canWrite=#pageInfo.writePermitted()# entity="contract" id=#contract_id# fwx=#tr.fwx#/>
</td>
</tr>
</cfoutput>
</table>
</cfif> --->
<layout:page section="footer"/>
+175
View File
@@ -0,0 +1,175 @@
<cfsilent>
<cfimport prefix="m" taglib="lib"/>
<cfimport prefix="c" taglib="lib/controls"/>
<cfimport prefix="d" taglib="lib/data"/>
<cfimport prefix="layout" taglib="layout"/>
</cfsilent><m:silent silent="No">
<cffunction name="plain2HtmClean">
<cfargument name="s" type="string"/>
<cfreturn request.plain2htm(request.cleanHtm(s))/>
</cffunction>
<cffunction name="cleanInput">
<cfargument name="s" type="string"/>
<cfreturn htmlEditFormat(s)/>
</cffunction>
<m:prepare_detail entity="contragent" accessObject="" key="contragent_id" pageInfoOut="pageInfo"/>
<d:bean readonly=true table="elma.companies" datasource="#request.DS#" output="d" status="status">
<d:param field="__id" type="uuid" key/>
<d:param field="__name" type="varchar" size="255" preprocessor=#cleanInput# forNull=""/>
<d:param field="_inn" type="varchar" size="255" preprocessor=#cleanInput# forNull=""/>
<d:param field="_kpp" type="varchar" size="255" preprocessor=#cleanInput# forNull=""/>
<d:param field="id_klienta" type="varchar" size="255" preprocessor=#cleanInput# forNull=""/>
<!--- *** билдер показывает... <d:param field="wz_id" type="varchar" size="255" preprocessor=#cleanInput# forNull=""/> --->
<!--- <d:param field="code_inn" type="varchar" size="255" preprocessor=#cleanInput# forNull=""/>
<d:param field="code_kpp" type="varchar" size="255" preprocessor=#cleanInput# forNull=""/> --->
</d:bean>
<m:dispatch_detail
usePRG="No"<!---*** --->
pageInfo=#pageInfo#
id="#d.__id#"
status=#pageInfo.status#
trackOut="tr"
idAttributesOut="id"
/>
<!--- decoration --->
<!--- <cfquery name="qDecoration" datasource="#request.DS#">
select
a.login as creator, a.shortname as creator_shortname, m.login as updater, m.shortname as updater_shortname
from contragent g
left outer join usr a on (g.creator_id=a.usr_id)
left outer join usr m on (g.updater_id=m.usr_id)
where g.contragent_id=<cfqueryparam attributeCollection=#id#/>
</cfquery> --->
</m:silent><!---
------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------
---><layout:page section="header" pageInfo=#pageInfo#>
<layout:attribute name="title">
<cfoutput>
Контрагент
<cfif len(d.__id)>
<b>#d.__name#</b>
[#d.__id#]
</cfif>
</cfoutput>
</layout:attribute>
</layout:page>
<!--- <cfif status.errorState GT 0>
<cfoutput><div class="err">#status.errorMessage#</div></cfoutput>
</cfif>
--->
<cfoutput>
<input type="hidden" name="__id" value="#d.__id#"/>
<input type="hidden" name="track" value="#tr.self#"/>
<input type="hidden" name="pass" value=""/><!--- pass marker to prevent save on submit --->
<div class="detail">
<div class="tr">
<div class="th">__id</div>
<div class="td">#d.__id#</div>
</div>
<div class="tr">
<div class="th">__name</div>
<div class="td">#d.__name#</div>
</div>
<div class="tr">
<div class="th">_inn</div>
<div class="td">#d._inn#</div>
</div>
<div class="tr">
<div class="th">_kpp</div>
<div class="td">#d._kpp#</div>
</div>
<div class="tr">
<div class="th">id_klienta</div>
<div class="td">#d.id_klienta#</div>
</div>
<!--- <div class="tr">
<div class="th">wz_id</div>
<div class="td">#d.wz_id#"/></div>
</div> --->
<!--- <div class="tr">
<div class="th">code_inn</div>
<div class="td">#d.code_inn#"/></div>
</div>
<div class="tr">
<div class="th">code_kpp</div>
<div class="td">#d.code_kpp#"/></div>
</div> --->
</div>
</cfoutput>
<!---
<layout:page section="extension" closeForm="Yes"/>
<cfif d.contragent_id GT 0>
<cfquery name="qContract">
select
d.contract_id
,d.contract
,d.dt_contract
,(select count(*) from specification s where s.contract_id=d.contract_id) as spec_cnt
from contract d
where d.contragent_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#d.contragent_id#"/>
order by 1
</cfquery>
<cfoutput>
<h4>Договоры (#qContract.recordCount#)</h4>
</cfoutput>
<table class="worktable">
<thead>
<tr>
<th><c:link_add canWrite=#pageInfo.writePermitted()# entity="contract" id="#contragent_id#" extra="contragent_id=#d.contragent_id#" fwx=#tr.fwx#/></th>
<th>Номер договора</th>
<th>Дата договора</th>
<th>Спецификаций</th>
<th></th>
</tr>
</thead>
<cfoutput query="qContract">
<tr>
<td>
<c:link_view_edit canWrite=#pageInfo.writePermitted()# entity="contract" id=#contract_id# fwx=#tr.fwx#/>
</td>
<td>#contract#</td>
<td class="c">
#dateFormat(dt_contract,'YYYY-MM-DD')#
</td>
<td class="c">
<cfif spec_cnt GT 0>#spec_cnt#</cfif>
</td>
<td class="c">
<c:link_del canWrite=#pageInfo.writePermitted()# entity="contract" id=#contract_id# fwx=#tr.fwx#/>
</td>
</tr>
</cfoutput>
</table>
</cfif> --->
<layout:page section="footer"/>
Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

+47
View File
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Creator: CorelDRAW X8 -->
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="78.6273mm" height="70.4009mm" version="1.1" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd"
viewBox="0 0 37746 33797"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<style type="text/css">
<![CDATA[
.fil3 {fill:none}
.fil2 {fill:#D7F372}
.fil4 {fill:#FEFEFE;fill-rule:nonzero}
.fil5 {fill:#638328;fill-rule:nonzero}
.fil1 {fill:url(#id1)}
.fil0 {fill:url(#id2)}
]]>
</style>
<clipPath id="id0">
<path d="M20432 0c8718,-38 15581,2266 15458,9209 -25,787 -197,745 -1206,434 -5376,-1662 -8578,-3016 -12410,-6248 -1067,-900 -1945,-1797 -2743,-2837 -478,-648 -8,-545 901,-558zm-18416 19428c1785,-4186 2803,-6725 6956,-9214 1814,-1088 3728,-1795 5744,-2401 5011,-1469 9917,-953 14495,540 1697,562 2833,1208 4123,2158 602,450 989,178 1872,-71 402,-113 1572,-529 1912,-305 933,615 -675,1120 -1291,1389 -1798,785 -1256,251 -1265,1780 -43,7030 -7302,11174 -13250,12374 -3409,688 -7029,1146 -9343,1499 -5916,900 -5060,-1185 -9071,-2819 -937,-381 -2531,-341 -2879,-1361 -223,-655 1540,-2751 1997,-3569z"/>
</clipPath>
<linearGradient id="id1" gradientUnits="userSpaceOnUse" x1="-740.954" y1="15224.8" x2="37478.6" y2="11458.4">
<stop offset="0" style="stop-opacity:1; stop-color:#C6C517"/>
<stop offset="1" style="stop-opacity:1; stop-color:#E7D900"/>
</linearGradient>
<linearGradient id="id2" gradientUnits="userSpaceOnUse" x1="-442.19" y1="20004.6" x2="37830.6" y2="16055.8">
<stop offset="0" style="stop-opacity:1; stop-color:#89A423"/>
<stop offset="1" style="stop-opacity:1; stop-color:#638429"/>
</linearGradient>
</defs>
<g id="Layer_x0020_1">
<metadata id="CorelCorpID_0Corel-Layer"/>
<path class="fil0" d="M22767 31689l-14060 2085c-2226,330 -4572,-2956 -6349,-3695 -1559,-649 -1653,-822 -1915,-2004 -266,-1196 -259,-3137 -401,-4460 -150,-1391 203,-1130 973,-2123 591,-795 964,-1292 1359,-2228 1413,-3396 2313,-5352 5285,-7695 3781,-2753 8236,-4067 12877,-4299 774,-89 484,-275 112,-747 -812,-1079 -1165,-2747 -1381,-4068 -68,-416 -308,-2197 198,-2372 228,-79 1093,72 1388,100 101,9 200,16 301,22 1094,51 2280,-41 2615,-17 4852,417 10503,1550 11899,7016 226,935 209,1325 200,2255 -2,142 -8,1026 126,1086 215,97 947,-1057 1467,133 110,344 145,764 169,1126 8,120 17,237 29,356 91,880 115,1755 53,2638 -23,319 -23,817 -223,1077 -611,795 -1576,1292 -2268,2065 -435,506 -635,1974 -834,2703 -720,2633 -1869,4361 -3594,4590l-7936 1054 -90 5402z"/>
<path class="fil1" d="M20432 0c8718,-38 15581,2266 15458,9209 -25,787 -197,745 -1206,434 -5376,-1662 -8578,-3016 -12410,-6248 -1067,-900 -1945,-1797 -2743,-2837 -478,-648 -8,-545 901,-558zm-18416 19428c1785,-4186 2803,-6725 6956,-9214 1814,-1088 3728,-1795 5744,-2401 5011,-1469 9917,-953 14495,540 1697,562 2833,1208 4123,2158 602,450 989,178 1872,-71 402,-113 1572,-529 1912,-305 933,615 -675,1120 -1291,1389 -1798,785 -1256,251 -1265,1780 -43,7030 -7302,11174 -13250,12374 -3409,688 -7029,1146 -9343,1499 -5916,900 -5060,-1185 -9071,-2819 -937,-381 -2531,-341 -2879,-1361 -223,-655 1540,-2751 1997,-3569z"/>
<g style="clip-path:url(#id0)">
<g id="_3107826610240">
<path id="1" class="fil2" d="M32620 15645c91,-46 98,-37 3,-91 -66,80 -20,59 -3,91zm-9180 173l399 13 94 3 24 -102c121,-34 39,27 76,-81l-104 -24c-76,-2 -129,-55 -130,-59 -3,-10 -11,-11 -18,-15l-68 -4c-94,14 -151,38 -213,69l-167 12 -8 120 12 65 103 3zm3362 -16369c31,57 -35,35 43,50 123,23 4,11 64,-18 -27,-64 39,-43 -41,-56 -131,-22 -7,-12 -66,24zm10290 3584c-14,-80 10,-36 -56,-77 -2,4 -94,5 -19,84 51,53 74,-7 75,-7zm2277 11808c100,-46 108,-71 4,-122 -65,81 -40,56 -4,122zm-598 -13384c72,-96 70,-72 -25,-113 -75,90 -74,70 25,113zm-486 7658c-47,-62 -81,7 -83,7 65,99 -66,22 64,80 3,-6 100,22 19,-87zm-14361 -9918c35,-131 44,-89 -39,-138 -4,7 -53,-26 -31,67 27,121 -23,26 70,71zm13953 15010c7,-87 -6,-35 -58,-63 -74,84 -46,57 -4,129 45,-22 53,54 62,-66zm1320 -15163c106,-113 26,-91 4,-126 -51,29 -67,-45 -62,71 4,73 20,40 58,55zm2646 15025c-2,-2 9,-68 -88,-57 -109,12 -37,7 -73,64 105,50 64,60 161,-7zm-292 -3726c48,-52 47,-33 49,-171 -84,-2 -93,-38 -195,78 -83,11 -33,-18 -92,47l115 91c47,-29 48,-35 123,-45zm-2986 3302c-113,22 -40,12 -65,57 182,135 184,-23 184,-24 -10,-6 19,-60 -119,-33zm-1300 1033c-76,-44 -26,-43 -193,-4 18,157 33,163 111,169 166,12 14,18 79,-36l3 -129zm-28 818c-15,-28 43,-120 -226,-46 35,72 -28,65 93,92 164,37 124,-39 133,-46zm-7887 -16516l182 4c21,-158 -15,-177 -161,-176l-21 172zm1556 1675l148 114c99,86 124,57 174,-16 -50,-145 -12,-36 -146,-105 -44,-243 65,-253 -76,-325 -82,93 -25,15 -43,187 -15,145 -10,6 -57,145zm-16717 6826c58,-32 47,42 53,-46 7,-83 4,-30 -50,-59l-24 38c3,61 -11,24 21,67zm-1336 -2651c25,-6 44,9 63,-22 77,-123 10,-42 -8,-80 -80,40 -47,5 -55,102zm-4579 -6954l-112 -3 26 95c101,-38 42,50 86,-92zm7494 3833c33,-24 94,21 33,-122 -79,33 -49,-52 -62,48 -20,150 -16,19 29,74zm14390 12465c-110,-30 -18,-3 -62,20 24,35 -18,154 116,33 -22,-35 -5,-40 -54,-53zm-16336 1107c44,-72 -19,-62 -22,-69 -108,42 -55,-27 -72,102 120,-4 51,36 94,-33zm-15555 -8727c0,-1 54,27 19,-104 -41,1 -53,-32 -83,34 -36,76 49,66 64,70zm29578 -7130c115,91 90,22 123,-26 -55,-41 62,-61 -72,-36 -85,16 -30,37 -51,62zm-15613 10133c8,-12 163,46 3,-107 -158,125 -4,106 -3,107zm19829 6238c-113,-3 -59,-5 -148,25 75,104 35,82 146,96l2 -121zm-1810 -750c-9,127 22,73 56,93 13,-18 98,-37 6,-177 -40,23 -55,-4 -62,84zm-22909 -1701c110,-49 103,-21 88,-170l-170 17 -8 103 29 61 61 -11zm17260 -7459c57,-32 46,52 67,-70 25,-145 -10,-61 -33,-93 -62,23 -49,-63 -69,61 -24,151 20,79 35,102zm6292 8218c-86,10 -54,14 -87,55 20,17 25,52 112,48 130,-7 69,-26 89,-71 -34,-23 -5,-44 -114,-32zm-18726 -12582l138 126c48,-78 33,-47 37,-156 -115,-27 -88,-44 -175,30zm5425 2089c112,8 43,39 121,-26l69 -111c-57,-38 50,-12 -63,-36 -108,-23 -8,-17 -111,3l-16 170zm199 -5155c68,-15 102,32 91,-91 -10,-106 -55,-86 -91,-103 -91,200 -13,173 0,194zm-4498 9344c44,-116 -2,-63 -8,-78 -188,-98 -154,47 -70,159 12,-9 44,9 78,-81zm-14595 -8298l-37 -85 -225 -25c13,84 -5,39 37,90 11,13 11,8 29,27 101,111 -29,62 100,79 134,17 77,-16 96,-28l0 -58zm16516 14224c-51,-40 -1,-28 -113,-50 -41,-8 -243,-20 -290,67 61,129 108,18 237,86 55,29 -10,50 104,69 198,32 132,-42 146,-52 -49,-181 23,-57 -89,-111l5 -9zm-15097 58c48,-69 44,-72 16,-145 -273,51 -22,42 -250,167 31,-165 -35,-99 -48,-114l-10 228 209 8 83 -144zm10508 -4775c26,-191 49,60 -34,-54 -80,69 -76,58 -4,123 52,-55 25,22 38,-69zm2333 -7579c33,-5 125,10 56,-109 -99,52 -45,-60 -56,109zm-3430 -2611c31,53 -29,36 45,50 112,21 9,9 62,-17 -23,-52 62,-39 -40,-56 -76,-13 -10,-11 -67,23zm-5194 1548c20,-171 28,-57 -48,-102 -23,40 -71,-39 -25,67 24,53 -2,25 73,35zm2622 14176c16,-129 5,-16 -32,-67 -96,48 -105,68 -4,128 34,-41 21,52 36,-61zm20631 -662c17,-119 -2,-25 -34,-66 -97,47 -110,67 -4,121 35,-34 24,49 38,-55zm-26456 -15122c101,69 78,57 133,-25 -30,-22 47,-55 -72,-37 -124,19 -29,27 -61,62zm-3047 11843c12,19 -43,82 103,51 57,-13 47,-31 63,-80 -75,-40 -83,-41 -168,-21l2 50zm590 1476c-68,85 -67,86 -5,161 100,-47 96,-110 5,-161zm9676 2249c132,-45 120,-6 96,-144 -185,-46 -50,-16 -91,31 11,22 4,32 23,36 49,12 16,9 52,-9 -39,-41 -1,-18 -75,-27 -8,6 -42,26 -44,28 -15,11 -32,39 -36,33 -3,-7 -12,13 -19,19l7 24c-83,-5 -17,-34 -119,21l-151 150c-7,14 -26,96 -30,118 184,-1 47,-2 195,-98 58,-38 107,-51 184,-77l17 -88 -9 -17zm-10949 -16354c55,-82 68,-123 -24,-178 -4,5 -49,-31 -45,89 4,131 35,74 69,89zm5381 2060c95,56 114,57 192,-23 -73,-75 -188,-91 -192,23zm4150 14183c1,-1 64,-22 50,-106 -19,-117 0,-36 -73,-72 -30,39 -121,103 23,178zm17483 -2004c-59,-80 -103,-72 -188,-35 18,24 -70,68 84,81 141,12 94,-39 104,-46zm-13680 -1675c141,42 169,46 247,-29 -37,-39 -45,-69 -145,-59 -99,10 -73,22 -102,88zm-8064 1221l-36 23c-90,81 -54,49 -56,120 261,25 188,-170 188,-171 -115,-7 34,-13 -60,2l-36 26c7,17 -3,42 39,48 3,1 16,-4 19,-4 5,0 15,-7 23,-10 -39,-35 6,-19 -81,-34zm8633 -1952c-7,-10 54,-79 -137,-26 9,87 13,131 90,196 33,-28 19,-1 55,-52 24,-33 -22,88 23,-39 49,-141 4,-71 -31,-79l-78 -1 25 81 53 -80zm-7088 2769c-11,-74 -88,-139 -148,-163l-43 119 162 129c15,-21 48,44 29,-85zm-7692 303l-2 61 261 28c11,-216 -161,-128 -259,-89zm39584 -10253c14,28 -26,64 65,64 135,1 27,20 78,-60 -44,-33 11,-44 -75,-39 -129,8 -18,-2 -68,35zm419 750c28,-36 34,52 41,-69 10,-164 -9,-60 -36,-101 -30,17 -56,-27 -71,73 -20,138 30,78 66,97zm3066 2473c55,-72 68,-95 66,-198 -92,-19 -136,-38 -155,50 -18,87 89,148 89,148zm2396 -3620c57,42 -52,30 106,49 159,20 20,7 113,-14 -22,-95 28,-126 -112,-132 -102,-5 -86,13 -107,97zm-718 4372l-51 -56c213,-116 92,-238 -70,-239 -152,-1 -176,38 -165,195l14 39c15,128 95,141 227,140l45 -79zm-11882 -7680c96,59 33,27 76,3l-58 -18c-3,-8 -12,11 -18,15zm-21198 15445c35,43 20,47 60,29 5,-2 14,-15 22,-22l-82 -7zm5007 1132l97 3 -6 -58c-40,-60 5,-36 -76,-65 -35,-12 -55,0 -88,1l5 117 68 2zm19326 -14421l-61 0c-35,54 -28,-70 -32,67 -4,136 11,60 30,93 73,-19 31,14 65,-50 146,-35 47,16 96,-68 -57,-55 15,-32 -98,-42zm-8429 13335c39,-6 206,-169 -164,-173 -70,95 -80,76 -102,170l266 3zm14571 -9261c47,74 57,123 127,4 -116,-124 -105,-20 -127,-4zm909 -1194c55,84 170,131 199,-23 -26,-14 -10,-39 -115,-26 -57,8 -60,10 -84,49zm271 2163c-1,-1 34,-56 -85,-37 -107,17 -28,-8 -84,61 38,68 -52,70 107,81 68,5 70,-17 106,-46 -12,-97 2,-33 -44,-59l-117 15 83 62c43,-50 20,-9 34,-77zm2227 -30c105,19 81,28 165,-11 -16,-86 -60,-131 -144,-155 -48,81 -43,60 -21,166zm-680 -1938c36,-37 13,13 35,-54 59,-184 69,-195 19,-219 -7,-2 -19,-13 -22,-4 -3,7 -75,-30 -95,109 -15,102 -6,135 63,168zm-7887 -1031c174,9 174,-15 198,-181l-195 0 -3 181zm-434 -3677c0,-132 -97,-207 -219,-204 -14,163 61,224 219,204zm9067 10670l-228 -20c15,143 32,200 191,182 20,-35 15,-15 29,-68 0,-1 7,-80 8,-94zm-11458 -8654l180 15c41,-77 53,-78 67,-187l-240 -2 -7 174zm-13484 -1787c67,65 -100,40 38,31 70,-5 24,3 66,-28 -77,-64 98,-40 -43,-30 -87,6 4,-25 -61,27zm15318 6420c8,8 -37,96 94,3 -76,-59 111,-37 -40,-27 -71,5 -10,-11 -54,24zm-4361 -5494c0,-176 44,-57 -80,-98 19,109 -24,65 80,98zm5777 11913c-52,-67 -18,-71 -104,-32 75,108 -101,-50 19,46 3,3 11,10 15,12 122,59 35,-5 70,-26zm452 -9192c-16,-105 17,-46 -64,-89 -51,58 -31,28 -37,112l0 24c139,141 57,117 171,135l19 -142 -89 -40zm1300 -184c26,36 -55,67 176,58 3,-16 70,-189 -107,-115 -68,28 -31,-2 -69,57zm-6645 5321c35,-145 -23,-89 -32,-106 -123,17 -84,-60 -108,72 -22,127 47,87 73,100 61,-30 38,56 67,-66zm12539 -5533c161,1 121,36 140,-122 -54,-35 -31,-46 -160,-30 -8,73 -19,77 20,152zm-7898 4642l158 -3 13 -151 -160 -4 -11 158zm-17042 -7038c56,111 45,115 104,4 -52,-38 -53,-32 -104,-4zm9439 14921c154,-74 34,-104 32,-108 -148,63 -33,108 -32,108zm-15492 -14617c77,-131 38,-84 -75,-106 31,146 -22,74 75,106zm2595 5412c115,-55 112,-64 4,-122 -16,20 -39,-42 -33,60 3,61 1,30 29,62zm3716 -5475c14,118 -32,80 92,86 38,-95 6,-127 -92,-86zm-11754 7101c6,-101 5,-86 -98,-105 -13,127 -2,118 98,105zm5801 -8233c54,-27 68,45 62,-68 -3,-75 -27,-45 -58,-61 -2,3 -85,14 -4,129zm-10835 7881c-39,-69 -44,-121 -135,-4 60,52 -67,23 67,40 113,15 27,-3 68,-36zm25397 -740c-39,10 -173,13 -98,95 96,105 86,-47 98,-95zm-2065 8351c-44,-72 23,-10 -75,-89 -65,-51 0,-9 -75,-42l-42 107 31 161c92,9 87,6 142,-32l19 -105zm-14954 -14214c87,52 55,48 150,6 -45,-139 -121,-139 -150,-6zm2674 8592c-160,2 -83,47 -93,81l164 16c3,-66 28,-97 -71,-97zm-12857 -11651c60,116 145,73 198,6 -88,-66 -119,-55 -198,-6zm14730 9603c8,31 -35,70 85,81 110,11 71,-14 85,-76 -83,-43 -68,-37 -170,-5zm-1945 -4959c-114,-51 -60,-57 -140,3l-4 58c93,64 166,73 228,-21 -41,-48 23,-26 -84,-40l-116 0c37,83 -28,35 83,68 54,-39 15,12 33,-68zm1791 10456c-76,-57 -141,-72 -205,22 16,13 16,57 118,48 109,-8 68,-30 87,-70zm6791 -1117c36,-46 36,70 46,-94 8,-128 -24,-68 -40,-87 -41,17 -64,-27 -71,84 -7,141 28,77 65,97zm-19845 -1831c156,4 126,-56 115,-191 -148,46 -119,6 -115,191zm28588 2560c110,14 138,-57 145,-166l-129 10c-85,158 -16,155 -16,156zm-24535 1960c-95,25 -67,45 -80,133 123,4 100,21 190,-35 -15,-82 23,-133 -110,-98zm-1340 -12555c34,-29 35,29 35,-82 -176,-85 -220,125 -198,245 233,90 139,21 170,-18l-9 -56 2 -89zm-138 10191c7,-3 15,-9 19,-11 187,-98 143,-30 160,-133 -81,-49 -97,-61 -235,49 -9,7 -14,11 -18,14l-10 -4 3 8c-6,4 -7,6 -36,40 48,43 -12,16 62,44 104,41 37,-1 55,-7zm8367 -12746l142 -3 17 -140c-107,-42 -56,-44 -174,-39 -39,107 -19,70 15,182zm13541 9864c19,-155 31,-118 -58,-202l-114 -68 -18 135c5,4 38,33 47,42 111,117 -30,57 143,93zm988 4753c45,-102 30,10 23,-135l-34 -127c-82,44 -10,4 -55,41l-47 40c-59,65 -45,-8 -44,128 63,55 64,54 157,53zm12225 -12623c69,-36 48,37 60,-51 11,-77 1,-29 -27,-74 -74,34 -47,-58 -61,47 -12,85 -16,23 28,78zm-541 532c79,-38 56,43 72,-73 18,-134 -33,-95 -37,-102 -62,28 -51,-64 -71,68 -26,164 18,78 36,107zm3249 -2408c42,-47 40,67 48,-70 9,-158 -18,-67 -43,-99 -62,25 -63,-61 -81,69 -20,138 47,86 76,100zm1303 9111c11,10 -39,54 99,53 166,-1 78,-27 103,-76 -9,-7 35,-50 -103,-50 -165,1 -70,41 -99,73zm-491 -3647c91,-9 105,-16 198,-88 -55,-161 -128,-160 -199,-171 8,167 44,104 1,259zm-24692 -3316c89,44 53,43 105,-26 -38,-27 54,-78 -66,-29 -4,1 -13,8 -16,10l-23 45zm13671 13200c-34,-129 31,-90 -104,-104 13,123 -20,66 104,104zm-2531 -392c-27,-46 15,-108 -118,-32 19,31 -50,43 47,68 133,33 20,3 71,-36zm7334 520c-76,-6 -56,36 -71,58 59,45 -67,20 67,36 129,15 17,4 69,-31 -26,-54 52,-54 -65,-63zm-2346 -1174c-22,-102 14,-11 -61,-51 -44,43 -78,-66 -39,94 19,78 18,22 64,42 41,-48 53,-4 36,-85zm-2672 1531c-126,3 -69,18 -100,66 34,27 41,99 222,7 -23,-40 -10,-76 -122,-73zm2389 -1391c-144,-10 -215,11 -139,175l166 10 -27 -185zm-13510 -6878c31,-55 21,-40 3,-86 -56,59 -65,-88 -32,42 34,130 -97,-14 29,44zm11036 7899c51,38 -7,20 62,28 135,17 -25,23 42,-24 -37,-35 4,-24 -62,-33 -161,-23 46,-43 -42,29zm-26597 -10879c62,73 10,58 96,32 -17,-44 72,-25 -23,-45 -72,-14 -23,-8 -73,13zm24877 10019c-13,-82 1,-14 -47,-36 -75,86 -26,63 26,92 24,-39 30,7 21,-56zm-13301 -13607c15,-24 58,33 23,-60 -25,-65 14,-8 -49,-43 -39,74 -63,63 26,103zm-1474 10770c72,-89 63,-70 -26,-109 -101,108 -21,86 26,109zm2490 -9768c5,-7 104,11 5,-148 -44,51 -53,-76 -44,73 6,81 4,33 39,75zm-455 582l45 -26c-21,-110 32,-69 -101,-93 -6,111 -40,72 56,119zm-2645 4875c5,-126 -3,-96 -98,-104 -11,117 -39,123 98,104zm-15387 -7335c18,35 -39,43 62,61 137,25 73,-13 98,-27 -5,-10 32,-155 -160,-34zm3775 14905c-5,113 34,83 37,87 96,-48 93,-123 5,-181 -22,29 -35,-53 -42,94zm16124 -7293c1,0 19,130 175,5 -14,-31 12,-58 -77,-63 -125,-7 -71,37 -98,58zm4169 4706c36,-17 59,39 73,-89 14,-124 -31,-78 -39,-88 -47,21 -58,-27 -69,83 -13,129 26,80 35,94zm-14149 1449c-78,-12 -84,28 -88,128l195 -3c-12,-79 -17,-110 -107,-125zm-10285 -377c144,13 156,25 270,-28 -59,-65 -141,-121 -249,-121l-21 149zm30877 -12750c85,40 49,47 105,-26 -20,-16 24,-117 -105,26zm-4545 -547c57,-82 74,-71 -25,-119 -65,93 -66,76 25,119zm6390 36c29,-122 42,-90 -84,-116 14,175 -38,71 84,116zm5154 2987c-1,45 -19,42 30,111 107,-34 39,71 81,-92 -1,-4 -13,-87 -13,-87 -16,-49 -13,-36 -31,-65 -83,37 -49,-29 -67,133zm-7078 -529c164,-26 122,59 107,-100 -108,-4 -71,-31 -107,100zm1289 -911c4,-125 47,-86 -67,-119 -93,100 -38,96 67,119zm2389 12606c-126,16 -58,-23 -117,61 78,102 120,95 117,-61zm-6679 -14484c93,-49 101,-26 33,-126 -50,15 -41,-45 -66,34 -45,140 4,62 33,92zm-6632 -463c15,26 -10,57 69,74 138,32 72,-15 95,-30 -35,-82 47,-48 -65,-68 -29,-6 -93,19 -99,24zm9162 3323c39,-11 64,56 82,-82 14,-103 -25,-89 -47,-113 -98,45 -81,123 -35,195zm11121 7323c77,-41 52,57 68,-98 6,-49 -11,-65 -20,-97 -60,22 -76,-44 -92,91 -17,134 36,91 44,104zm-6944 6433l64 2c35,-109 52,-107 -11,-201 -29,8 -65,-56 -82,91 -8,64 4,48 29,108zm-9851 -12707c33,-80 14,-192 -50,-252 -80,-76 -14,-26 -117,-47 51,222 26,39 90,163 44,86 -28,59 77,136zm17007 11129c-5,-4 -12,-10 -18,-14l-82 -58c-96,106 -9,225 150,201 10,-144 19,-76 -50,-129zm-14523 -7357l6 118 177 17 4 -157c-119,-17 -93,-25 -187,22zm1634 621c122,-10 52,43 137,-39 82,-80 30,-20 53,-141l-179 10 -11 170zm4069 -5651l169 46c4,-99 16,-85 -35,-146 -85,-102 -17,-50 -154,-73l20 173zm10176 12053c-10,-85 13,-6 -49,-52 -38,41 -37,-9 -30,69 9,97 -12,14 55,43 37,-56 37,58 24,-60zm-8682 -13172c37,61 -40,39 51,54 69,12 24,3 66,-21 -13,-32 49,-134 -117,-33zm2107 1274c32,-19 113,33 33,-122 -78,35 -50,-47 -63,48 -17,129 -11,23 30,74zm-2180 -3663l-108 -3c2,174 -2,49 42,106 98,-52 42,59 66,-103zm10237 6623c21,-30 58,43 35,-71 -21,-101 17,-22 -68,-66 -52,93 -66,71 33,137zm-4681 8279c36,-113 -28,-91 -30,-94 -79,34 -36,-30 -61,65 -8,29 10,72 15,95 50,-25 47,25 76,-66zm1712 -10475c91,-11 72,27 106,-40 54,-109 -37,-81 -62,-94l-37 44c-16,57 -18,8 -7,90zm-2158 653c14,19 -16,66 79,65 118,-2 32,5 75,-60 -18,-16 33,-129 -154,-5zm-9161 -4516c140,63 104,33 149,-46 -10,-8 40,-74 -77,-47 -186,44 -11,10 -72,93zm14791 10390c-148,-15 -74,13 -105,64 54,49 -82,47 102,53 102,4 98,-46 99,-47 -19,-29 7,-60 -96,-70zm-7396 -6688c36,71 -84,46 67,61 7,-6 18,-26 21,-20l74 -89c49,-90 34,-58 -1,-120 -66,20 -27,3 -73,42 -4,4 -10,10 -14,14 -4,4 -10,10 -14,14 -5,5 -12,11 -16,16l-35 33 -9 49zm3325 -2979c18,41 -50,73 94,76 129,2 71,-21 95,-70 -6,-6 38,-52 -90,-53 -164,-1 -55,12 -99,47zm-4326 1161l115 0c21,-126 29,-84 -30,-190 -116,49 -118,87 -85,190zm5264 1728c3,-4 48,17 51,-93 3,-169 -3,-47 -45,-100 -39,16 -76,-51 -89,107 -7,77 16,64 83,86zm3737 8908c127,-174 17,-185 6,-201 -65,17 -98,-21 -96,100 3,114 51,86 90,101zm-578 -7651c-69,-84 28,-32 -83,-63 -47,-14 -89,-4 -137,1 12,162 117,193 220,62zm-10792 -2729c100,-7 112,56 202,-184l-175 3 -27 181zm11216 4612c69,-72 57,-54 46,-178l-200 -7c-4,7 -10,9 -11,18l-76 95c135,22 67,-7 160,87l81 -15zm-25274 1701c77,60 7,56 87,3 -48,-47 101,-40 -34,-29 -73,6 -3,-17 -53,26zm-2320 -4177c8,14 14,124 93,3 -55,-40 95,-28 -36,-22 -55,3 -22,-1 -57,19zm3531 6166c27,41 -51,47 54,45 61,-2 16,-6 40,-42 -34,-25 -1,-17 -55,-23 -3,0 -17,14 -19,7 -3,-7 -13,9 -20,13zm9742 -9188c141,-30 64,23 96,-75 -192,-10 -27,10 -96,75zm-816 7909c14,-101 12,5 -30,-35 -126,99 -4,94 -3,96 46,-55 21,17 33,-61zm4718 4713c-57,112 -6,23 20,71 19,-13 146,-53 23,-91 -70,-21 -30,-5 -43,20zm-8122 -431c-16,-86 16,-10 -58,-43 -83,124 13,93 34,107 35,-58 47,63 24,-64zm17489 -3007c175,99 121,19 148,5 -163,-141 -131,-17 -148,-5zm-22342 4930c132,-4 153,38 191,-77l-183 -33c-126,37 -56,-3 -107,63 48,51 -83,44 99,47zm12980 -12068c-5,14 -15,15 -16,31 -2,16 -12,19 -13,27 -6,30 -6,60 -4,92l176 14 5 -153 -148 -11zm3361 -432c36,-54 25,-37 3,-87 -60,72 -60,-95 -28,43 33,144 -77,-37 25,44zm-4106 70c11,-16 62,31 29,-65 -27,-79 22,-7 -54,-51 -28,44 -74,-63 -27,70 23,65 -11,17 52,46zm4107 -1014c84,-42 48,57 62,-54 19,-151 13,-10 -29,-78 -90,38 -52,-66 -66,48 -12,105 -22,20 33,84zm5309 -1291c25,-37 79,60 36,-83 -31,-104 27,-9 -60,-59 -32,47 -83,-71 -36,83 27,91 -22,17 60,59zm1248 6583c63,-42 37,35 61,-54 36,-132 -10,-66 -27,-91 -56,21 -39,-53 -66,42 -50,177 2,67 32,103zm-3412 -2551c58,-28 78,64 72,-75 -4,-112 -22,-47 -68,-70 0,1 -117,-7 -4,145zm-290 -1225c21,58 -53,43 42,70 192,56 47,8 103,-36 -35,-66 28,-44 -52,-65 -126,-33 -82,23 -93,31zm-5356 -3095l-18 46c15,128 58,97 106,82 112,-34 73,-59 86,-77 -19,-13 -52,-43 -84,-53l-90 2zm8115 7257c60,-74 70,111 51,-115 -8,-93 -53,-79 -74,-92 -6,7 -48,-10 -51,93 -7,206 -25,60 74,114zm-358 -3417c71,-45 53,62 74,-83 25,-183 -18,-80 -39,-116 -80,37 -60,-87 -83,79 -26,191 22,83 48,120zm-17157 14c84,70 -122,41 42,30 72,-5 22,6 65,-27 -62,-52 99,-38 -41,-29 -76,5 -12,-10 -66,26zm5328 -1528c64,-38 48,39 53,-51 7,-103 14,-24 -49,-60 -33,49 -32,66 -4,111zm-27615 8986c78,-37 55,63 54,-88 -92,2 -45,-22 -73,27 -47,84 8,41 19,61zm32764 3684c-10,-69 1,-14 -45,-37 -107,108 -16,75 26,101 17,-36 27,-9 19,-64zm-6438 -13319c1,0 47,9 52,-34 12,-113 25,-18 -49,-67 -15,24 -88,9 -3,101zm-2549 -1315c-17,8 -170,44 -28,87 58,17 34,0 42,-20 45,-117 9,-15 -14,-67zm4500 3122c50,-16 41,47 55,-34 13,-73 3,-24 -22,-71 -54,37 -107,11 -33,105zm100 11390c59,41 -62,18 67,32 141,16 7,10 72,-28 -141,-125 -131,-11 -139,-4zm5906 333c26,-38 129,23 33,-116 -108,38 -98,26 -33,116zm-36586 -127c129,-18 2,10 67,-35 -65,-124 -157,-104 -185,26 57,9 59,18 118,9zm29127 1316c73,-30 40,-35 106,4 -33,22 14,19 -51,22 -116,5 -14,2 -55,-26zm-38 58l179 5 2 -117 -181 -1 0 113zm-23361 -15949c1,-1 61,10 45,-97 -16,-103 8,-32 -68,-78 -13,20 -65,-31 -41,104 21,124 2,35 64,71zm7079 11660c-101,8 -43,-8 -107,52 -56,54 -46,20 -62,107l176 18 -7 -177zm27110 -785c-83,-43 -52,-52 -103,26 49,34 -62,39 59,24 76,-9 15,3 44,-50zm-1211 -2487c86,-45 122,22 33,-115 -52,20 -45,-52 -59,40 -13,86 -25,15 26,75zm849 -5816c135,-10 77,32 107,-104 -166,22 -89,-39 -107,104zm-8045 -1393l59 -2c61,-97 37,-142 -53,-191 -5,7 -123,39 -6,193zm-12585 2344c3,-126 9,-31 -32,-70 -25,25 -18,13 -37,64l39 57 30 -51zm21445 8401c-173,28 -5,162 -5,162 17,-23 34,53 35,-88 2,-133 2,-16 -30,-74zm-7726 -10714c54,-16 48,46 60,-34 14,-86 9,-15 -27,-73 -49,31 -121,-28 -33,107zm2226 -437c29,-40 52,53 35,-69 -15,-105 -2,-34 -59,-73 -14,17 -58,-43 -43,72 17,126 -14,33 67,70zm-13381 14473c-108,-44 -32,2 -69,25 153,144 93,45 120,32 -37,-65 17,-30 -51,-57zm-16107 -2399c103,-46 70,-13 61,-117 -96,10 -54,-27 -90,34 -46,78 29,83 29,83zm6804 -10029c-8,-5 -18,-24 -24,-15l-95 -9c0,144 -25,145 119,124l0 -100c-90,37 -68,-13 -76,69 108,-5 13,38 76,-69zm-11048 7103c11,-112 26,21 -39,-41l8 93c60,-55 22,37 31,-52zm6 -5040c76,71 -99,41 38,30 70,-5 11,13 56,-27 -53,-44 90,-32 -36,-25 -65,4 -11,-8 -58,22zm701 2991c38,31 32,40 85,3 -102,-100 -85,-3 -85,-3zm38576 5668c152,93 87,13 102,3 -42,-43 17,-22 -57,-32l-45 29z"/>
<path class="fil2" d="M22443 33531c91,-46 99,-37 3,-91 -65,80 -19,59 -3,91zm-9179 174l399 12 94 3 23 -102c121,-33 40,27 77,-81l-104 -24c-77,-2 -129,-55 -130,-59 -3,-10 -12,-11 -18,-15l-68 -4c-94,14 -152,38 -213,70l-167 11 -9 121 13 64 103 4zm3362 -16370c31,57 -35,35 43,50 123,23 4,11 64,-17 -27,-65 39,-44 -41,-57 -132,-21 -7,-12 -66,24zm10290 3584c-14,-80 9,-36 -56,-77 -3,4 -94,6 -19,84 51,53 74,-6 75,-7zm2277 11808c100,-46 108,-71 3,-122 -64,81 -39,56 -3,122zm-598 -13384c72,-96 69,-72 -26,-113 -75,90 -73,70 26,113zm-487 7658c-46,-62 -80,7 -82,7 65,99 -67,22 63,80 4,-5 100,22 19,-87zm-14360 -9918c34,-131 44,-88 -39,-138 -4,7 -53,-26 -32,67 28,121 -23,26 71,71zm13953 15010c6,-87 -6,-35 -58,-63 -75,84 -46,57 -4,130 44,-23 53,54 62,-67zm1319 -15162c106,-114 26,-92 4,-127 -51,29 -67,-45 -61,71 4,73 20,40 57,56zm2647 15024c-2,-2 8,-68 -88,-57 -109,12 -38,7 -73,64 105,50 64,60 161,-7zm-293 -3726c49,-51 48,-33 50,-171 -85,-2 -93,-38 -195,78 -83,12 -33,-18 -93,47l116 91c47,-29 48,-34 122,-45zm-2986 3302c-112,22 -39,12 -64,57 182,135 183,-23 184,-23 -10,-7 18,-61 -120,-34zm-1299 1033c-77,-44 -27,-43 -194,-4 19,157 34,164 112,169 166,12 14,18 78,-36l4 -129zm-29 818c-14,-28 44,-120 -225,-46 34,72 -28,65 93,92 164,37 124,-39 132,-46zm-7886 -16516l181 4c22,-158 -15,-177 -160,-176l-21 172zm1555 1675l149 114c98,86 124,57 174,-16 -50,-145 -13,-36 -146,-105 -44,-243 65,-253 -76,-325 -82,93 -26,15 -43,187 -15,145 -11,7 -58,145zm-16716 6826c57,-32 46,42 53,-46 6,-83 4,-30 -50,-59l-24 38c3,61 -12,24 21,67zm-1337 -2651c26,-6 45,9 64,-22 76,-123 9,-42 -9,-80 -79,40 -46,5 -55,102zm-4578 -6954l-112 -3 26 95c100,-38 42,50 86,-92zm7494 3833c33,-24 94,21 33,-122 -79,33 -50,-52 -63,48 -20,150 -15,19 30,74zm14390 12465c-111,-30 -19,-3 -63,20 25,35 -17,155 117,33 -23,-35 -5,-39 -54,-53zm-16337 1107c45,-72 -18,-62 -21,-68 -108,41 -55,-28 -72,101 119,-4 51,36 93,-33zm-15554 -8727c0,0 54,27 19,-104 -42,1 -53,-32 -84,34 -35,76 50,66 65,70zm29578 -7130c115,91 90,22 123,-26 -55,-41 62,-61 -72,-36 -85,16 -31,37 -51,62zm-15614 10133c9,-12 164,46 4,-107 -159,125 -4,106 -4,107zm19830 6238c-114,-3 -59,-5 -148,25 75,104 35,82 145,96l3 -121zm-1810 -750c-9,127 22,73 56,93 12,-18 98,-37 5,-177 -39,23 -54,-4 -61,84zm-22909 -1701c109,-48 103,-21 88,-170l-170 17 -8 103 28 61 62 -11zm17260 -7459c57,-31 46,52 67,-70 25,-145 -11,-61 -33,-93 -63,23 -49,-63 -69,61 -24,151 20,79 35,102zm6292 8218c-87,10 -54,14 -87,55 20,17 25,52 112,48 129,-7 69,-26 89,-70 -34,-24 -5,-45 -114,-33zm-18726 -12582l138 126c48,-78 33,-47 37,-155 -115,-28 -88,-44 -175,29zm5425 2089c111,8 43,39 121,-26l69 -111c-57,-37 50,-12 -63,-36 -108,-23 -9,-17 -111,3l-16 170zm198 -5155c69,-15 103,32 92,-91 -10,-106 -55,-86 -92,-103 -90,200 -13,173 0,194zm-4497 9344c43,-116 -3,-63 -8,-78 -188,-98 -155,47 -70,159 12,-9 44,9 78,-81zm-14595 -8298l-38 -84 -224 -26c12,84 -6,39 36,90 11,13 12,8 29,28 102,110 -28,62 101,78 134,18 76,-16 96,-27l0 -59zm16516 14224c-52,-40 -1,-28 -113,-50 -42,-8 -243,-19 -291,67 61,129 109,18 238,86 55,29 -10,50 104,69 197,32 132,-42 145,-52 -48,-181 24,-57 -88,-111l5 -9zm-15098 58c48,-69 45,-72 17,-145 -274,51 -23,42 -250,167 30,-165 -35,-99 -48,-113l-11 227 209 8 83 -144zm10508 -4775c27,-191 50,60 -34,-54 -79,69 -75,58 -4,123 52,-55 26,22 38,-69zm2333 -7579c33,-5 126,10 57,-109 -99,52 -45,-60 -57,109zm-3429 -2611c31,53 -29,36 45,50 112,21 8,9 62,-17 -23,-52 62,-39 -41,-56 -76,-13 -10,-11 -66,23zm-5194 1548c20,-171 28,-57 -49,-102 -23,40 -71,-39 -24,67 24,53 -2,25 73,35zm2621 14176c16,-129 6,-16 -31,-67 -97,48 -106,68 -4,128 34,-41 21,52 35,-61zm20632 -662c16,-119 -2,-25 -34,-66 -97,47 -111,67 -4,122 35,-34 23,48 38,-56zm-26456 -15122c101,69 77,57 133,-25 -31,-22 47,-55 -73,-37 -124,19 -29,27 -60,62zm-3048 11843c12,19 -42,82 104,51 57,-12 47,-31 63,-80 -76,-39 -83,-41 -168,-21l1 50zm591 1476c-69,86 -68,86 -5,161 100,-47 96,-110 5,-161zm9675 2249c133,-45 121,-5 97,-144 -185,-45 -50,-16 -91,31 11,22 3,32 23,36 48,12 16,9 52,-9 -40,-40 -1,-18 -75,-27 -8,6 -43,27 -44,28 -15,11 -33,39 -36,33 -3,-7 -13,13 -19,19l7 24c-84,-5 -18,-34 -119,21l-151 150c-8,14 -26,96 -31,118 184,-1 48,-2 196,-98 58,-38 107,-51 184,-77l16 -87 -9 -18zm-10948 -16354c55,-82 67,-123 -24,-178 -4,5 -50,-31 -46,89 4,132 36,74 70,89zm5381 2060c95,56 114,57 192,-23 -74,-75 -188,-91 -192,23zm4150 14183c1,-1 63,-22 50,-106 -19,-117 0,-36 -74,-72 -29,39 -120,103 24,178zm17482 -2004c-59,-80 -103,-72 -188,-35 18,24 -69,68 85,81 140,12 94,-39 103,-46zm-13680 -1675c142,42 170,46 247,-29 -36,-39 -44,-68 -144,-58 -99,9 -73,21 -103,87zm-8064 1221l-36 23c-90,81 -54,49 -55,120 261,25 188,-170 188,-171 -115,-6 33,-13 -60,2l-37 26c8,17 -2,42 39,48 4,1 17,-4 20,-4 4,0 15,-7 22,-10 -39,-35 7,-19 -81,-34zm8634 -1952c-7,-10 54,-79 -138,-26 10,87 13,131 91,196 33,-28 19,-1 54,-52 25,-33 -21,88 23,-39 49,-141 5,-71 -30,-79l-79 -1 26 81 53 -80zm-7088 2769c-11,-74 -89,-139 -148,-163l-44 119 162 129c15,-21 49,45 30,-85zm-7692 303l-2 61 260 28c12,-216 -160,-128 -258,-89zm39584 -10253c14,28 -26,64 64,64 136,1 28,20 79,-60 -44,-33 10,-44 -75,-38 -129,7 -19,-3 -68,34zm419 750c28,-36 34,52 41,-69 10,-164 -9,-60 -36,-101 -30,17 -56,-27 -71,73 -20,138 30,78 66,97zm3065 2473c56,-72 68,-95 66,-198 -91,-19 -135,-38 -154,50 -19,87 88,148 88,148zm2397 -3620c57,42 -53,30 105,50 159,19 21,7 114,-15 -23,-95 27,-126 -112,-132 -103,-5 -87,13 -107,97zm-719 4372l-51 -56c213,-116 93,-238 -69,-239 -152,-1 -176,38 -165,195l14 39c14,128 95,141 226,140l45 -79zm-11881 -7680c95,59 33,27 75,3l-58 -18c-2,-8 -11,11 -17,15zm-21198 15445c35,43 20,47 60,29 5,-2 14,-15 21,-22l-81 -7zm5007 1132l96 3 -5 -58c-40,-60 5,-36 -76,-65 -36,-12 -55,0 -88,1l4 117 69 2zm19325 -14421l-61 0c-35,54 -27,-70 -32,67 -4,136 12,61 31,94 73,-20 31,13 65,-51 145,-35 46,16 95,-68 -56,-55 16,-32 -98,-42zm-8429 13335c40,-6 207,-169 -164,-173 -69,95 -80,76 -101,170l265 3zm14572 -9261c47,74 56,123 127,4 -117,-124 -105,-20 -127,-4zm909 -1194c54,84 169,131 199,-23 -27,-13 -10,-39 -116,-25 -56,7 -60,9 -83,48zm271 2163c-1,-1 33,-56 -85,-37 -108,17 -29,-7 -85,61 38,68 -51,70 108,81 68,5 70,-17 106,-46 -12,-97 2,-33 -44,-59l-117 16 83 62c42,-51 19,-10 34,-78zm2226 -30c105,20 81,29 165,-11 -16,-86 -60,-131 -144,-155 -47,81 -42,60 -21,166zm-680 -1938c37,-37 13,14 35,-54 59,-183 70,-195 20,-219 -8,-1 -19,-13 -23,-4 -2,7 -74,-30 -94,109 -15,102 -7,135 62,168zm-7886 -1031c174,9 174,-15 198,-181l-195 0 -3 181zm-435 -3677c1,-132 -96,-207 -218,-204 -14,163 61,224 218,204zm9068 10670l-229 -20c16,143 33,200 192,182 19,-35 15,-15 28,-68 1,-1 7,-80 9,-94zm-11458 -8654l179 16c42,-78 53,-79 68,-188l-240 -2 -7 174zm-13484 -1787c67,65 -101,40 38,31 69,-5 24,3 66,-28 -78,-63 97,-40 -43,-30 -88,6 4,-25 -61,27zm15318 6420c8,8 -38,96 94,3 -76,-59 111,-37 -40,-27 -71,5 -10,-11 -54,24zm-4361 -5494c0,-176 44,-57 -80,-98 19,110 -24,65 80,98zm5776 11913c-52,-67 -17,-71 -103,-32 75,108 -101,-50 18,46 3,3 12,10 15,12 123,59 36,-5 70,-26zm452 -9192c-15,-105 18,-46 -63,-89 -52,58 -31,28 -37,112l0 24c138,141 57,117 171,135l18 -141 -89 -41zm1300 -184c26,36 -55,67 177,58 3,-16 69,-189 -108,-115 -67,28 -30,-2 -69,57zm-6644 5321c34,-145 -23,-89 -32,-106 -123,17 -85,-60 -108,72 -22,127 47,87 73,100 61,-30 38,56 67,-66zm12539 -5533c161,1 121,36 140,-122 -54,-35 -31,-46 -161,-30 -7,73 -19,77 21,152zm-7899 4642l158 -3 14 -151 -161 -4 -11 158zm-17041 -7038c56,111 45,115 103,4 -51,-38 -52,-32 -103,-4zm9438 14921c155,-74 35,-103 33,-108 -148,63 -33,108 -33,108zm-15491 -14617c76,-131 38,-84 -75,-106 30,146 -22,74 75,106zm2595 5412c114,-55 112,-64 4,-122 -17,20 -39,-42 -33,60 3,62 0,30 29,62zm3715 -5475c14,118 -32,80 93,86 37,-95 5,-127 -93,-86zm-11753 7101c5,-101 4,-86 -99,-104 -13,126 -1,117 99,104zm5801 -8233c54,-27 68,45 62,-68 -4,-75 -27,-45 -58,-61 -3,3 -85,14 -4,129zm-10835 7881c-39,-69 -44,-121 -135,-4 59,52 -68,23 66,40 114,15 28,-3 69,-36zm25397 -740c-39,10 -173,13 -98,95 96,105 85,-47 98,-95zm-2065 8351c-44,-72 23,-10 -75,-89 -65,-51 0,-9 -75,-42l-43 107 31 161c93,9 88,6 142,-32l20 -105zm-14954 -14214c87,52 55,48 150,6 -45,-139 -121,-139 -150,-6zm2674 8593c-160,1 -84,46 -93,80l164 16c3,-66 28,-97 -71,-96zm-12857 -11652c59,116 145,73 198,6 -89,-66 -119,-55 -198,-6zm14729 9603c9,31 -34,70 86,81 110,11 71,-13 85,-75 -84,-44 -68,-38 -171,-6zm-1945 -4959c-113,-51 -59,-57 -140,3l-3 59c93,63 166,72 228,-22 -42,-48 23,-26 -85,-40l-115 0c37,83 -28,35 82,68 55,-38 15,12 33,-68zm1792 10456c-77,-56 -141,-72 -205,23 16,12 15,56 118,47 109,-8 68,-30 87,-70zm6791 -1117c36,-46 36,70 46,-94 7,-128 -25,-68 -41,-87 -41,17 -64,-27 -70,84 -8,141 28,77 65,97zm-19845 -1831c156,4 126,-56 115,-191 -148,47 -119,6 -115,191zm28588 2560c110,14 138,-57 145,-166l-129 10c-85,158 -17,155 -16,156zm-24536 1960c-95,25 -67,45 -79,133 122,4 100,21 190,-35 -16,-82 22,-133 -111,-98zm-1339 -12555c34,-29 35,29 35,-82 -176,-85 -220,125 -198,245 232,90 139,21 169,-18l-8 -56 2 -89zm-138 10191c6,-3 15,-9 19,-11 187,-98 143,-30 160,-133 -81,-49 -97,-61 -235,49 -9,7 -15,11 -19,14l-10 -4 4 8c-6,4 -7,6 -36,41 47,43 -13,15 61,44 105,40 38,-2 56,-8zm8367 -12746l142 -3 16 -140c-106,-42 -55,-43 -174,-39 -38,108 -18,70 16,182zm13540 9864c20,-155 32,-118 -57,-201l-114 -69 -18 135c4,4 38,33 46,42 112,117 -30,57 143,93zm988 4753c45,-102 30,10 24,-135l-34 -127c-82,44 -11,4 -56,41l-47 40c-58,65 -44,-8 -43,128 63,55 64,54 156,53zm12226 -12623c69,-36 48,37 60,-51 10,-77 0,-29 -27,-74 -74,34 -47,-58 -62,47 -11,85 -16,23 29,78zm-541 532c79,-38 56,43 72,-73 18,-134 -33,-95 -37,-102 -62,28 -51,-64 -72,68 -25,164 18,78 37,107zm3249 -2408c42,-47 39,67 47,-70 10,-158 -17,-67 -42,-99 -63,25 -63,-60 -82,69 -19,138 47,86 77,100zm1303 9111c11,10 -39,54 99,53 165,-1 78,-27 103,-76 -9,-7 34,-50 -103,-50 -165,1 -71,41 -99,73zm-492 -3647c92,-9 106,-16 198,-88 -55,-161 -128,-160 -198,-171 8,167 44,104 0,259zm-24691 -3316c88,44 53,43 105,-26 -39,-27 54,-78 -66,-29 -4,1 -13,8 -16,10l-23 45zm13670 13200c-33,-129 32,-90 -103,-104 13,123 -21,66 103,104zm-2530 -391c-27,-47 15,-109 -119,-33 20,31 -50,44 47,68 133,33 20,3 72,-35zm7333 519c-75,-6 -55,36 -70,58 59,45 -67,20 67,36 128,15 17,5 68,-31 -26,-54 53,-54 -65,-63zm-2346 -1174c-21,-102 14,-11 -60,-51 -44,43 -78,-66 -39,94 19,78 18,22 64,42 41,-48 52,-4 35,-85zm-2671 1531c-126,3 -69,18 -100,67 33,26 41,98 222,6 -23,-40 -11,-75 -122,-73zm2389 -1391c-144,-10 -216,11 -140,175l167 10 -27 -185zm-13510 -6878c31,-55 21,-40 2,-86 -55,59 -65,-88 -31,42 34,130 -97,-14 29,44zm11036 7899c51,38 -7,20 62,28 135,17 -26,24 42,-24 -37,-35 3,-24 -62,-33 -162,-23 46,-43 -42,29zm-26597 -10879c61,73 10,58 96,32 -17,-44 72,-25 -24,-45 -72,-14 -22,-8 -72,13zm24876 10019c-12,-82 2,-14 -47,-36 -75,86 -25,63 27,92 24,-39 30,7 20,-56zm-13300 -13607c15,-24 58,33 23,-60 -25,-65 14,-8 -49,-43 -39,74 -64,63 26,103zm-1474 10770c72,-89 63,-70 -26,-109 -102,108 -21,86 26,109zm2490 -9768c5,-7 104,11 5,-148 -45,51 -53,-76 -44,73 5,81 3,34 39,75zm-455 582l45 -26c-21,-109 31,-69 -102,-93 -6,111 -39,73 57,119zm-2646 4875c5,-126 -2,-96 -98,-104 -10,117 -38,124 98,104zm-15387 -7335c19,35 -38,43 63,61 137,25 73,-13 97,-27 -4,-10 32,-155 -160,-34zm3776 14905c-5,113 33,83 36,87 97,-48 94,-123 6,-180 -22,28 -35,-54 -42,93zm16124 -7293c1,0 19,130 175,5 -14,-31 11,-58 -77,-63 -125,-7 -71,37 -98,58zm4168 4706c37,-17 60,39 74,-88 13,-125 -31,-79 -39,-89 -47,21 -58,-27 -69,83 -13,129 25,80 34,94zm-14149 1449c-77,-12 -83,28 -88,128l196 -3c-13,-79 -18,-110 -108,-125zm-10285 -377c145,13 156,25 271,-27 -60,-66 -141,-122 -250,-121l-21 148zm30878 -12750c85,40 49,48 105,-26 -21,-16 24,-117 -105,26zm-4545 -547c57,-82 74,-71 -26,-119 -64,93 -65,76 26,119zm6389 36c29,-122 43,-90 -83,-116 14,175 -39,72 83,116zm5155 2988c-2,44 -19,42 29,111 108,-35 40,70 81,-93 0,-4 -13,-87 -13,-87 -15,-49 -13,-36 -31,-65 -82,38 -49,-29 -66,134zm-7078 -530c164,-26 121,59 106,-100 -107,-4 -71,-31 -106,100zm1288 -911c5,-125 48,-86 -66,-119 -93,100 -38,96 66,119zm2390 12606c-127,16 -58,-23 -117,61 77,102 120,95 117,-61zm-6680 -14484c93,-49 102,-26 33,-126 -50,15 -40,-45 -66,34 -44,140 5,62 33,92zm-6631 -463c15,26 -10,57 69,75 138,31 72,-16 95,-31 -35,-82 47,-48 -66,-68 -28,-5 -93,19 -98,24zm9161 3323c39,-11 65,56 83,-82 13,-103 -26,-89 -48,-112 -98,44 -81,122 -35,194zm11122 7323c77,-41 52,57 68,-98 5,-49 -11,-64 -20,-96 -60,21 -77,-45 -93,90 -16,134 36,91 45,104zm-6944 6433l64 2c34,-109 52,-107 -11,-201 -30,8 -66,-56 -83,91 -7,64 4,48 30,108zm-9852 -12707c33,-80 15,-192 -49,-252 -81,-76 -14,-26 -117,-47 50,222 25,40 89,163 45,86 -28,59 77,136zm17007 11129c-5,-4 -12,-10 -17,-14l-83 -58c-95,106 -8,225 151,201 10,-144 18,-76 -51,-129zm-14522 -7357l6 118 177 17 4 -157c-119,-17 -94,-25 -187,22zm1633 621c122,-9 53,43 137,-39 83,-80 31,-20 54,-141l-180 10 -11 170zm4070 -5651l169 46c4,-99 16,-85 -35,-146 -85,-102 -17,-49 -154,-73l20 173zm10175 12053c-9,-85 14,-6 -49,-52 -37,41 -36,-9 -29,69 9,97 -12,14 55,43 36,-56 37,58 23,-60zm-8682 -13171c38,60 -39,38 51,53 70,12 25,3 66,-21 -12,-32 50,-133 -117,-32zm2108 1273c32,-19 113,33 33,-122 -78,35 -51,-47 -63,49 -17,128 -11,22 30,73zm-2180 -3663l-109 -3c3,174 -2,49 43,106 98,-52 42,59 66,-103zm10237 6624c21,-31 58,42 35,-72 -21,-101 16,-22 -69,-66 -51,93 -65,71 34,138zm-4681 8278c35,-113 -29,-91 -30,-94 -79,35 -36,-30 -61,65 -8,30 9,72 15,95 49,-25 47,25 76,-66zm1712 -10475c90,-11 72,27 105,-40 54,-109 -36,-81 -61,-94l-37 44c-16,57 -18,8 -7,90zm-2159 653c14,19 -15,66 80,65 117,-2 32,5 75,-60 -19,-16 33,-129 -155,-5zm-9160 -4516c140,63 103,33 149,-46 -10,-8 40,-74 -77,-47 -186,44 -11,10 -72,93zm14791 10390c-149,-15 -74,13 -105,64 54,49 -82,47 102,53 102,4 97,-46 99,-47 -19,-29 7,-60 -96,-70zm-7396 -6688c36,71 -84,46 66,62 8,-7 18,-27 22,-21l74 -89c49,-90 34,-58 -1,-120 -66,20 -27,3 -73,42 -5,4 -10,10 -14,14 -5,4 -11,10 -15,14 -4,5 -11,12 -16,16l-35 34 -8 48zm3324 -2979c19,41 -49,73 95,76 129,2 70,-21 95,-70 -7,-6 38,-52 -90,-53 -165,-1 -56,12 -100,47zm-4325 1161l115 0c20,-126 28,-84 -30,-190 -117,49 -118,87 -85,190zm5264 1728c2,-3 48,17 50,-92 4,-170 -3,-48 -44,-101 -39,16 -77,-51 -90,107 -6,77 17,64 84,86zm3736 8908c128,-174 17,-185 7,-200 -65,16 -98,-21 -96,99 2,114 50,86 89,101zm-577 -7651c-69,-84 28,-31 -83,-63 -48,-14 -90,-4 -138,1 13,162 117,193 221,62zm-10793 -2729c100,-7 113,56 202,-184l-174 3 -28 181zm11216 4612c69,-72 58,-54 46,-178l-199 -7c-4,7 -10,9 -12,18l-76 95c135,22 68,-7 161,87l80 -15zm-25273 1701c76,60 6,56 86,3 -47,-47 102,-40 -34,-29 -72,6 -2,-17 -52,26zm-2321 -4177c9,14 14,125 94,3 -55,-40 95,-28 -36,-22 -55,3 -22,-1 -58,19zm3532 6166c27,41 -52,47 54,45 61,-2 15,-6 40,-42 -34,-25 -1,-17 -55,-23 -4,0 -17,14 -19,7 -3,-7 -13,9 -20,13zm9741 -9188c141,-29 65,23 97,-75 -192,-10 -27,11 -97,75zm-816 7909c15,-101 13,5 -29,-35 -126,99 -5,94 -3,96 46,-55 21,17 32,-61zm4719 4713c-57,112 -6,24 19,71 20,-12 147,-53 24,-91 -71,-21 -31,-5 -43,20zm-8123 -431c-15,-86 16,-10 -58,-43 -82,124 13,93 35,107 35,-58 46,63 23,-64zm17490 -3007c175,100 121,20 148,5 -164,-141 -131,-17 -148,-5zm-22342 4930c132,-4 153,38 190,-77l-182 -33c-126,37 -57,-3 -107,63 47,51 -83,44 99,47zm12980 -12068c-5,14 -15,15 -17,31 -2,16 -11,19 -13,27 -5,31 -5,60 -3,92l176 14 5 -153 -148 -11zm3361 -432c36,-54 25,-37 3,-87 -60,72 -60,-95 -28,43 33,144 -77,-37 25,44zm-4106 70c11,-16 62,31 29,-65 -28,-79 21,-7 -55,-51 -27,44 -74,-63 -27,70 23,65 -11,17 53,46zm4107 -1014c83,-42 48,57 62,-54 19,-151 12,-10 -29,-78 -91,38 -53,-66 -66,49 -13,104 -23,19 33,83zm5309 -1291c25,-37 79,60 36,-83 -31,-103 26,-8 -61,-59 -32,47 -82,-71 -36,83 28,92 -21,17 61,59zm1248 6583c63,-42 37,35 61,-54 35,-132 -11,-66 -27,-91 -56,21 -40,-53 -67,42 -50,177 3,67 33,103zm-3413 -2551c58,-28 79,64 73,-75 -5,-112 -22,-47 -68,-70 -1,1 -117,-7 -5,145zm-289 -1224c21,57 -53,42 41,69 192,56 47,8 104,-36 -35,-66 27,-44 -52,-65 -126,-33 -82,23 -93,32zm-5357 -3096l-17 46c15,129 58,97 106,82 112,-34 72,-59 86,-77 -20,-13 -52,-43 -84,-53l-91 2zm8116 7257c60,-74 70,111 51,-114 -8,-94 -53,-80 -74,-93 -6,8 -48,-10 -52,93 -7,206 -24,60 75,114zm-359 -3417c72,-45 54,62 74,-83 26,-183 -17,-80 -38,-116 -80,37 -61,-87 -83,79 -26,191 21,83 47,120zm-17157 14c85,70 -121,41 43,30 71,-4 21,6 65,-27 -62,-52 98,-38 -42,-29 -76,5 -12,-10 -66,26zm5329 -1528c63,-38 47,39 53,-51 6,-102 14,-24 -50,-60 -32,49 -31,66 -3,111zm-27615 8986c78,-36 55,63 54,-88 -92,3 -46,-22 -73,28 -47,83 8,40 19,60zm32764 3684c-10,-69 0,-14 -45,-36 -107,107 -16,74 26,100 17,-35 26,-9 19,-64zm-6439 -13319c1,0 48,9 52,-33 12,-114 25,-19 -48,-68 -16,24 -89,9 -4,101zm-2549 -1315c-16,8 -169,44 -28,87 59,17 35,0 43,-20 45,-117 8,-15 -15,-67zm4501 3122c50,-16 41,47 55,-34 13,-73 3,-24 -23,-71 -53,37 -106,11 -32,105zm100 11390c59,41 -62,18 66,32 141,16 8,10 73,-28 -142,-125 -131,-11 -139,-4zm5906 333c25,-38 129,23 33,-116 -109,38 -98,26 -33,116zm-36586 -127c129,-18 2,10 67,-34 -65,-125 -157,-104 -185,25 57,9 59,18 118,9zm29127 1317c73,-31 40,-35 105,3 -33,22 15,19 -51,22 -115,5 -13,3 -54,-25zm-38 57l179 5 2 -117 -181 -1 0 113zm-23361 -15949c1,-1 61,10 45,-96 -16,-104 8,-33 -69,-78 -13,19 -64,-32 -40,103 21,124 1,35 64,71zm7078 11660c-100,8 -43,-8 -106,52 -56,54 -46,20 -62,107l175 18 -7 -177zm27110 -785c-82,-43 -51,-52 -102,26 49,34 -62,39 58,24 76,-9 15,3 44,-50zm-1210 -2487c86,-45 122,22 32,-114 -51,19 -45,-53 -58,39 -14,86 -25,15 26,75zm849 -5816c135,-10 76,32 106,-104 -166,22 -89,-39 -106,104zm-8045 -1393l58 -2c62,-97 37,-142 -52,-191 -5,7 -124,39 -6,193zm-12585 2344c3,-126 9,-31 -32,-70 -26,25 -18,13 -37,64l38 57 31 -51zm21445 8402c-173,27 -5,161 -5,161 16,-23 33,53 35,-88 2,-133 2,-16 -30,-73zm-7726 -10715c54,-16 48,46 60,-34 13,-86 8,-15 -27,-73 -49,31 -122,-28 -33,107zm2226 -437c29,-40 52,53 35,-69 -16,-105 -3,-34 -60,-73 -13,17 -57,-43 -42,72 16,126 -15,33 67,70zm-13381 14473c-109,-44 -32,2 -69,25 153,144 93,45 120,33 -37,-65 17,-30 -51,-58zm-16107 -2399c103,-46 70,-13 61,-117 -97,10 -54,-27 -90,34 -46,78 29,83 29,83zm6804 -10029c-8,-5 -18,-24 -24,-15l-96 -9c1,144 -24,145 120,124l0 -100c-90,37 -68,-13 -76,69 108,-5 13,38 76,-69zm-11049 7103c12,-112 26,21 -38,-41l7 93c60,-55 22,37 31,-52zm7 -5040c76,71 -99,41 37,30 71,-5 11,13 56,-27 -52,-44 90,-32 -35,-25 -65,4 -11,-8 -58,22zm700 2992c39,30 32,39 86,2 -102,-100 -86,-3 -86,-2zm38577 5667c152,93 87,13 102,3 -42,-43 16,-22 -58,-32l-44 29z"/>
</g>
</g>
<path class="fil3" d="M20432 0c8718,-38 15581,2266 15458,9209 -25,787 -197,745 -1206,434 -5376,-1662 -8578,-3016 -12410,-6248 -1067,-900 -1945,-1797 -2743,-2837 -478,-648 -8,-545 901,-558zm-18416 19428c1785,-4186 2803,-6725 6956,-9214 1814,-1088 3728,-1795 5744,-2401 5011,-1469 9917,-953 14495,540 1697,562 2833,1208 4123,2158 602,450 989,178 1872,-71 402,-113 1572,-529 1912,-305 933,615 -675,1120 -1291,1389 -1798,785 -1256,251 -1265,1780 -43,7030 -7302,11174 -13250,12374 -3409,688 -7029,1146 -9343,1499 -5916,900 -5060,-1185 -9071,-2819 -937,-381 -2531,-341 -2879,-1361 -223,-655 1540,-2751 1997,-3569z"/>
<path class="fil4" d="M10113 32164l548 -85c566,-87 655,-815 655,-1696 0,-1108 -152,-1559 -630,-1485l-573 89 0 3177zm-872 -3711l1541 -239c770,-120 1425,167 1425,1818l0 225c0,1013 -203,2283 -1374,2464l-1592 246 0 -4514z"/>
<path class="fil4" d="M14753 30269l-349 -2047 -421 2167 770 -120zm-922 -2527l1171 -182 1019 4358 -943 146 -216 -1141 -987 152 -274 1218 -935 145 1165 -4696z"/>
<polygon class="fil4" points="17968,31617 17096,31752 17096,27924 16014,28092 16014,27404 19050,26934 19050,27622 17968,27790 "/>
<path class="fil5" d="M24269 30700l88 -3885 -824 115 -106 4640 2357 -329 17 -755 -1532 214zm2552 396l105 -4640 -824 115 -106 4640 825 -115zm3488 -5112l-525 1811c-157,575 -298,1154 -410,1687l-17 3c-83,-518 -193,-1044 -319,-1586l-423 -1679 -1020 143 -395 4680 752 -105 124 -1798c41,-577 85,-1269 109,-1855l17 -3c87,553 207,1162 334,1668l432 1780 624 -87 566 -1950c157,-539 327,-1176 462,-1748l17 -3c-16,472 -6,1216 3,1822l37 1793 785 -109 -139 -4606 -1014 142zm2380 3547l29 -1291 1399 -196 16 -730 -1398 196 25 -1123 1483 -207 17 -748 -2307 322 -106 4640 2396 -334 17 -749 -1571 220z"/>
<path class="fil4" d="M21036 29298l-350 -2048 -420 2166 770 -118zm-923 -2529l1172 -182 1019 4359 -943 145 -217 -1141 -986 152 -274 1218 -936 145 1165 -4696z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 69 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 174 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 173 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 173 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 179 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 255 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

+16
View File
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<style type="text/css">
.st0{fill:#555555;}
</style>
<g>
<path class="st0" d="M476.7,88.3h-88.3c0-48.8-39.5-88.3-88.3-88.3s-88.3,39.5-88.3,88.3h-88.3c-19.5,0-35.3,15.8-35.3,35.3v88.3
C39.5,211.9,0,251.4,0,300.1s39.5,88.3,88.3,88.3v88.3c0,19.5,15.8,35.3,35.3,35.3h123.6v-35.3c0-29.3,23.7-53,53-53s53,23.7,53,53
V512h123.6c19.5,0,35.3-15.8,35.3-35.3V353.1h-35.3c-29.3,0-53-23.7-53-53s23.7-53,53-53H512V123.6
C512,104.1,496.2,88.3,476.7,88.3z M388.4,300.1c0,48.8,39.5,88.3,88.3,88.3v88.3h-88.3c0-31.5-16.8-60.7-44.1-76.5
c-27.3-15.8-61-15.8-88.3,0c-27.3,15.8-44.1,44.9-44.1,76.5h-88.3V353.1H88.3c-29.3,0-53-23.7-53-53s23.7-53,53-53h35.3V123.6
h123.6V88.3c0-29.3,23.7-53,53-53s53,23.7,53,53v35.3h123.6v88.3C427.9,211.9,388.4,251.4,388.4,300.1z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 141 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 222 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1023 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 889 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 81 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

+16
View File
@@ -0,0 +1,16 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z" />
<polyline points="14 2 14 8 20 8" />
<path d="M10 12a1 1 0 0 0-1 1v1a1 1 0 0 1-1 1 1 1 0 0 1 1 1v1a1 1 0 0 0 1 1" />
<path d="M14 18a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1 1 1 0 0 1-1-1v-1a1 1 0 0 0-1-1" />
</svg>

After

Width:  |  Height:  |  Size: 498 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 725 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 996 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 743 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 972 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 517 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 665 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 692 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 691 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 71 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 71 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 537 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 305 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 350 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 346 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1000 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 54 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 54 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 103 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 241 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 362 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 243 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 51 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 84 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 990 B

+54
View File
@@ -0,0 +1,54 @@
<cfimport prefix="m" taglib="../lib"/>
<cfimport prefix="c" taglib="../lib/controls"/>
<cfparam name="ATTRIBUTES.fwx" default=""/>
<cfparam name="ATTRIBUTES.thisUrl" default=""/>
<cfset i18=request.i18/>
<!---<style>ul#mainmenu li.menu-item-noaction a.inline{display:inline;}</style>--->
<cfoutput>
<ul id="mainmenu">
<cfif request.usrAuthenticated()></cfif>
<!--- <li class="menu-title">Реестры</li>
<c:menu_item acl="" page="contract_ls.cfm" label="Договоры"/>
<c:menu_item acl="" page="specification_ls.cfm" label="Спецификации"/>
<c:menu_item acl="" page="agreement_ls.cfm" label="Сделки"/>
<c:menu_item acl="" page="specification_item_ls.cfm" label="Экземпляры услуг"/> --->
<li class="menu-title">Отчеты</li>
<c:menu_item acl="" page="payg.cfm" label="PAYG"/>
<!--- <c:menu_item acl="" page="detail_daily_rpt.cfm" label="Детализация по дням"/>
<c:menu_item acl="" page="income_daily_rpt.cfm" label="Выручка по дням"/>
<c:menu_item acl="" page="income_monthly_rpt.cfm" label="Выручка по месяцам"/> --->
<!--- <li class="menu-title">Справочники</li>
<c:menu_item acl="" page="svc_ls.cfm" label="Сервисы"/>
<c:menu_item acl="" page="contragent_ls.cfm" label="Контрагенты"/>
<c:menu_item acl="" page="measure_ls.cfm" label="Единицы измерения"/>
<c:menu_item acl="" page="usr_ls.cfm" label="Пользователи"/>
--->
<li class="menu-title">"Пользователь"</li>
<cfif request.usrAuthenticated()>
<cfquery name="qUsr" datasource="#request.DS#">
select shortname/*, login, firstname, middlename, lastname*/
from usr
where usr_id=<cfqueryparam cfsqltype="CF_SQL_INTEGER" value=#request.usr_id#/>
</cfquery>
<li class="menu-item-noaction">#qUsr.shortname#</li> <!---#request.usr_id#--->
<c:menu_item acl="" page="password.cfm" queryString="#ATTRIBUTES.fwx#" label="Смена пароля"/>
<c:menu_item acl="" page="logout.cfm" queryString="target_page=#URLEncodedFormat(ATTRIBUTES.thisUrl)#" label="Выход"/>
<cfelse>
<c:menu_item acl="" page="saml/login.cfm" queryString="target_page=#URLEncodedFormat(ATTRIBUTES.thisUrl)#" label="Вход через WebSSO"/>
<c:menu_item acl="" page="login.cfm" queryString="#ATTRIBUTES.fwx#" label="Вход"/>
<c:menu_item acl="" page="logout.cfm" queryString="target_page=#URLEncodedFormat(ATTRIBUTES.thisUrl)#" label="Выход"/>
</cfif>
</ul>
</cfoutput>
<cfexit method="exittag"/>
-241
View File
@@ -1,241 +0,0 @@
<cfset dt_finish=createDateTime(year(Now()),month(Now()),1,0,0,0)/>
<cfset dt_start=dateAdd('m',-1,dt_finish)/>
Нужно еще применить политики бесплатного минимума
<!---
<cfquery name="qCode" datasource="dwh">
select distinct p.code
from elma.deals d
join elma.deals_services siv on (d.__id=ANY(siv.deal))
join elma.service_parametrs p on (p.__id = ANY(siv.params))
join elma.companies k on (d._companies=k.__id)
join elma.additional_agreements aa on (aa.__id = ANY(siv.additional_agreement))
join elma.aggrements a on (aa.contract_uid = a.__id)
where p.type=3 AND aa.is_actual
order by p.code
</cfquery>
<cfdump var=#qCode#/>
<cfquery name="qSpec" datasource="dwh">
select k.id_klienta, p.code, p.price, p.discount, k.__name as contragent, a.__name as contract, d.__name as deal, siv.abstractive_service as abstract_service, siv.modifier, siv.user_description
,p.__name as metric, p.ed_izm
--, aa.is_actual
from elma.deals d
join elma.deals_services siv on (d.__id=ANY(siv.deal))
join elma.service_parametrs p on (p.__id = ANY(siv.params))
join elma.companies k on (d._companies=k.__id)
join elma.additional_agreements aa on (aa.__id = ANY(siv.additional_agreement))
join elma.aggrements a on (aa.contract_uid = a.__id)
where p.type=3 AND aa.is_actual
order by k.id_klienta, p.code
</cfquery>
здесь имеем список кодов с ценами и WZ. Каждому коду можно поставить в соответствие запрос, который даст по нему выборку. Изредка один запрос может вывести 2 кода, но разбить на 2 запроса легко. Кроме того, запросы можно объединить через union в один - может быть, так будет лучше читаться (быстрее выполняться не будет)
<cfdump var=#qSpec#/>
<cfquery name="qComputing" datasource="billing-vc">
select 'WZ'||to_char(tenant.wzcode,'FM00000') as wz, vdc.name as vdc_name,
case
when vdc.name like '%-v1cl1-%' then 'iaas.ngc.i29'
when vdc.name like '%-v1cl2-%' then 'iaas.ngc.i31'
when vdc.name like '%-v1cl4-%' then 'iaas.ngc.a28'
when vdc.name like '%-v1cl6-%' then 'iaas.ngc.i28'
else 'unknown' end as code,
sum(cpu_used/cpu_speed)/4. as core_h,
sum(mem_used)/1024/4. as gb_h
from ngcloud_ru.capacity_resource
join ngcloud_ru.vdc on capacity_resource.vdc_id=vdc.id
join ngcloud_ru.tenant on tenant.id=vdc.tenant_id
where tenant.wzcode > 0
AND capacity_resource.timestamp >= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_start#/>
AND capacity_resource.timestamp < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_finish#/>
group by tenant.wzcode, vdc.name
order by tenant.wzcode, vdc.name;
</cfquery>
<cfdump var=#qComputing#/>
<cfquery name="qStorage" datasource="billing-vc">
select 'WZ'||to_char(tenant.wzcode,'FM00000') as wz, vdc.name as vdc_name,
case
when vdc.name like '%-v1cl1-%' then 'iaas.ngc.i29'
when vdc.name like '%-v1cl2-%' then 'iaas.ngc.i31'
when vdc.name like '%-v1cl4-%' then 'iaas.ngc.a28'
when vdc.name like '%-v1cl6-%' then 'iaas.ngc.i28'
else 'unknown' end as code,
storage_profile_types.name as storage_profile_type_name,
sum("limit")/1024./4 as gb_h_limit, -- 4 потому, что сбор раз в 15 минут
sum(used)/1024./4 as gb_h_used
from ngcloud_ru.capacity_storage
join ngcloud_ru.vdc on capacity_storage.vdc_id=vdc.id
join ngcloud_ru.tenant on tenant.id=vdc.tenant_id
join ngcloud_ru.storage_profile_types on capacity_storage.storage_profile_types_id=storage_profile_types.id
where tenant.wzcode > 0
AND capacity_storage.timestamp >= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_start#/>
AND capacity_storage.timestamp < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_finish#/>
group by tenant.wzcode, vdc.name, storage_profile_types.name
order by tenant.wzcode, vdc.name, storage_profile_types.name;
</cfquery>
<cfdump var=#qStorage#/>
<cfquery name="qS3Vol" datasource="billing-s3">
select
sum(bucket_stat.usage_rgw_main_size_actual) as vol,
case
when bucket_stat.placement_id = 1 then 'paas.s3.ceph.vol'
when bucket_stat.placement_id = 2 then 'paas.s3.cphc.vol'
else 'unknown' end as code,
'WZ'||lpad(bucket_stat.owner, 5, '0') as wz -- *** здесь код приведен к целому, а потом к строке
from s3billing.bucket_stat
join s3billing.placement ON s3billing.placement.id=bucket_stat.placement_id
join s3billing.bucket_info ON bucket_info.id=bucket_stat.bucket_id
where bucket_stat.placement_id in (1,2)
AND bucket_stat.timestamp_addition >= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_start#/>
AND bucket_stat.timestamp_addition < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_finish#/>
group by bucket_stat.owner, bucket_stat.placement_id
order by bucket_stat.owner, bucket_stat.placement_id;
</cfquery>
<cfdump var=#qS3Vol#/>
<cfquery name="qS3OpsDefaultPlacement" datasource="billing-s3">
select sum(ops) as ops,
case
when category.name like 'get%' then 'get'
when category.name like 'put%' then 'put'
when category.name like 'post%' then 'post'
when category.name like 'list%' then 'list'
else 'unknown' end as op,
'WZ'||lpad(user_info.name, 5, '0') as wz
from s3billing.usage_bucket_by_user
join s3billing.user_info on usage_bucket_by_user.user_id=user_info.id
join s3billing.category on usage_bucket_by_user.category_id=category.id
join s3billing.bucket_info on usage_bucket_by_user.bucketid=bucket_info.id
join s3billing.placement on bucket_info.placement_id=placement.id and placement.name='default-placement'
where 1=1
AND usage_bucket_by_user.time >= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_start#/>
AND usage_bucket_by_user.time < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_finish#/>
group by user_info.name, category.name
order by user_info.name, category.name;
</cfquery>
<cfdump var=#qS3OpsDefaultPlacement#/>
<cfquery name="qS3OpsDefault" datasource="billing-s3">
select sum(ops) as ops,
case
--when category.name like 'get%' then 'get' /*get встречается*/
when category.name like 'put%' then 'put'
--when category.name like 'post%' then 'post'
when category.name like 'list%' then 'list'
else 'unknown' end as op,
'WZ'||lpad(user_info.name, 5, '0') as wz
from s3billing.usage_bucket_by_user
join s3billing.user_info on usage_bucket_by_user.user_id=user_info.id
join s3billing.category on usage_bucket_by_user.category_id=category.id
--join s3billing.bucket_info on usage_bucket_by_user.bucketid=bucket_info.id
--join s3billing.placement on bucket_info.placement_id=placement.id and placement.name='default-placement'
where s3billing.usage_bucket_by_user.bucketid='0'
AND usage_bucket_by_user.time >= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_start#/>
AND usage_bucket_by_user.time < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_finish#/>
group by user_info.name, category.name
order by user_info.name, category.name;
</cfquery>
<cfdump var=#qS3OpsDefault#/>
--->
Трафик хранится в той же таблице, что и остальной юзадж, можно было бы доставать в общем резалтсете
<cfquery name="qS3TrafficDefaultPlacement" datasource="billing-s3">
select sum(bytes_sent) as bytes,
placement.name as placement
'WZ'||lpad(user_info.name, 5, '0') as wz
from s3billing.usage_bucket_by_user
join s3billing.user_info on usage_bucket_by_user.user_id=user_info.id
join s3billing.category on usage_bucket_by_user.category_id=category.id
join s3billing.bucket_info on usage_bucket_by_user.bucketid=bucket_info.id
join s3billing.placement on bucket_info.placement_id=placement.id
where 1=1
AND usage_bucket_by_user.time >= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_start#/>
AND usage_bucket_by_user.time < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_finish#/>
group by user_info.name
order by user_info.name;
</cfquery>
<cfdump var=#qS3TrafficDefaultPlacement#/>
<cfquery name="qS3TrafficDefault" datasource="billing-s3">
select sum(bytes_sent) as bytes,
'WZ'||lpad(user_info.name, 5, '0') as wz
from s3billing.usage_bucket_by_user
join s3billing.user_info on usage_bucket_by_user.user_id=user_info.id
join s3billing.category on usage_bucket_by_user.category_id=category.id
--join s3billing.bucket_info on usage_bucket_by_user.bucketid=bucket_info.id
--join s3billing.placement on bucket_info.placement_id=placement.id AND placement.name='default-placement'
where s3billing.usage_bucket_by_user.bucketid='0'
AND usage_bucket_by_user.time >= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_start#/>
AND usage_bucket_by_user.time < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_finish#/>
group by user_info.name
order by user_info.name;
</cfquery>
<cfdump var=#qS3TrafficDefault#/>
<!---
задача (вызванная сыростью базы биллинга)
смапить код параметра с VDC (1:n)
iaas.ngc.i31.ram-m
iaas.ngc.a28.ram-m
cl01:
7 хостов Lenovo ThinkSystem SR650 -[7X06CTO1WW]-
2 процессора Xeon(R) Gold 6226R 16 ядер 32 потока каждый 2.9 ГГц
1.25тб озу в каждом.
В 4 из 7 есть по 4 GPU NVIDIA A16 16GB в каждом.
cl01-vsan:
16 хостов Lenovo ThinkSystem SR650 -[7X06CTO1WW]-
2 процессора Xeon(R) Gold 6226R 16 ядер 32 потока каждый 2.9 ГГц
1.25тб озу в каждом.
В 9 из 16 есть по 4 GPU NVIDIA A16 16GB в каждом.
cl02:
10 Huawei 2488H V5
4 процессора Xeon(R) Gold 6254 18 ядер 36 потоков каждый. 3.1 ГГц
2тб озу в каждом.
5 Huawei Atlas 800 (Model 3010)
2 процессора Xeon(R) Gold 6254 18 ядер 36 потоков каждый. 3.1 ГГц
1.5тб озу в каждом.
cl04-vsan:
10 Apex AR320-12
2 процессора AMD EPYC 7543 32 ядра 64 потока каждый. 2.8 ГГц
2тб озу в каждом.
18 Apex AR320-12-E7543
2 процессора AMD EPYC 7543 32 ядра 64 потока каждый. 2.8 ГГц
2тб озу в каждом.
cl05-1c:
1 Asus RS720A-E12-RS24U
2 процессора AMD EPYC 9274F 24 ядра 48 потоков каждый. 4.05 ГГц
1тб озу.
7 ручная сборка
MB Asus ProArt B650-Creator
Процессор AMD Ryzen 9 7950X 16 ядер 32 потока каждый. 4.5 ГГц
192гб озу каждый.
1 ручная сборка
процессор AMD Ryzen Threadripper PRO 5995WX 64 ядра 128 потоков каждый. 2.7 ГГц
512гб озу.
cl06-vsan:
15 R320
2 процессора Xeon(R) Gold 6342 24 ядра 48 потоков каждый. 2.8 ГГц
1тб озу каждый.
Xeon(R) Gold 6226R 2.9 ГГц
Xeon(R) Gold 6254 3.1 ГГц
AMD EPYC 7543 2.8 ГГц
AMD EPYC 9274F 4.05 ГГц
AMD Ryzen 9 7950X 4.5 ГГц
AMD Ryzen Threadripper PRO 5995WX 2.7 ГГц
Xeon(R) Gold 6342 2.8 ГГц --->
+1 -457
View File
@@ -1,457 +1 @@
<cflocation url="payg.cfm" addtoken="No"/>
<cfset dt_finish=createDateTime(year(Now()),month(Now()),1,0,0,0)/>
<cfset dt_start=dateAdd('m',-1,dt_finish)/>
<cfset hours=dateDiff('h',dt_start,dt_finish)/>
Внимание! округление вверх при расчете метрик
<cfdump var=#dt_start#/>
<cfdump var=#dt_finish#/>
<cfdump var=#hours#/>
<!--- Нужно еще применить политики бесплатного минимума --->
<!---
<cfquery name="qCode" datasource="dwh">
select distinct p.code
from elma.deals d
join elma.deals_services siv on (d.__id=ANY(siv.deal))
join elma.service_parametrs p on (p.__id = ANY(siv.params))
join elma.companies k on (d._companies=k.__id)
join elma.additional_agreements aa on (aa.__id = ANY(siv.additional_agreement))
join elma.aggrements a on (aa.contract_uid = a.__id)
where p.type=3 AND aa.is_actual
order by p.code
</cfquery>
<cfdump var=#qCode#/>
<cfquery name="qSpec" datasource="dwh">
select k.id_klienta, p.code, p.price, p.discount, k.__name as contragent, a.__name as contract, d.__name as deal, siv.abstractive_service as abstract_service, siv.modifier, siv.user_description
,p.__name as metric, p.ed_izm
--, aa.is_actual
from elma.deals d
join elma.deals_services siv on (d.__id=ANY(siv.deal))
join elma.service_parametrs p on (p.__id = ANY(siv.params))
join elma.companies k on (d._companies=k.__id)
join elma.additional_agreements aa on (aa.__id = ANY(siv.additional_agreement))
join elma.aggrements a on (aa.contract_uid = a.__id)
where p.type=3 AND aa.is_actual
order by k.id_klienta, p.code
</cfquery>
здесь имеем список кодов с ценами и WZ. Каждому коду можно поставить в соответствие запрос, который даст по нему выборку. Изредка один запрос может вывести 2 кода, но разбить на 2 запроса легко. Кроме того, запросы можно объединить через union в один - может быть, так будет лучше читаться (быстрее выполняться не будет)
<cfdump var=#qSpec#/>
<cfquery name="qComputing" datasource="billing-vc">
select 'WZ'||to_char(tenant.wzcode,'FM00000') as wz, vdc.name as vdc_name,
case
when vdc.name like '%-v1cl1-%' then 'iaas.ngc.i29'
when vdc.name like '%-v1cl2-%' then 'iaas.ngc.i31'
when vdc.name like '%-v1cl4-%' then 'iaas.ngc.a28'
when vdc.name like '%-v1cl6-%' then 'iaas.ngc.i28'
else 'unknown' end as code,
sum(cpu_used/cpu_speed)/4. as core_h,
sum(mem_used)/1024/4. as gb_h
from ngcloud_ru.capacity_resource
join ngcloud_ru.vdc on capacity_resource.vdc_id=vdc.id
join ngcloud_ru.tenant on tenant.id=vdc.tenant_id
where tenant.wzcode > 0
AND capacity_resource.timestamp >= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_start#/>
AND capacity_resource.timestamp < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_finish#/>
group by tenant.wzcode, vdc.name
order by tenant.wzcode, vdc.name;
</cfquery>
<cfdump var=#qComputing#/>
<cfquery name="qStorage" datasource="billing-vc">
select 'WZ'||to_char(tenant.wzcode,'FM00000') as wz, vdc.name as vdc_name,
case
when vdc.name like '%-v1cl1-%' then 'iaas.ngc.i29'
when vdc.name like '%-v1cl2-%' then 'iaas.ngc.i31'
when vdc.name like '%-v1cl4-%' then 'iaas.ngc.a28'
when vdc.name like '%-v1cl6-%' then 'iaas.ngc.i28'
else 'unknown' end as code,
storage_profile_types.name as storage_profile_type_name,
sum("limit")/1024./4 as gb_h_limit, -- 4 потому, что сбор раз в 15 минут
sum(used)/1024./4 as gb_h_used
from ngcloud_ru.capacity_storage
join ngcloud_ru.vdc on capacity_storage.vdc_id=vdc.id
join ngcloud_ru.tenant on tenant.id=vdc.tenant_id
join ngcloud_ru.storage_profile_types on capacity_storage.storage_profile_types_id=storage_profile_types.id
where tenant.wzcode > 0
AND capacity_storage.timestamp >= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_start#/>
AND capacity_storage.timestamp < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_finish#/>
group by tenant.wzcode, vdc.name, storage_profile_types.name
order by tenant.wzcode, vdc.name, storage_profile_types.name;
</cfquery>
<cfdump var=#qStorage#/>
--->
<!---
"placement" "size_gb" "get_10k" "put_10k" "bytes_sent_gb"
HOT_FREE_LIMIT 1 10 1 100
--->
<!--- надо дисконтировать не ГБ-часы а ГБ-месяцы --->
<cfquery name="qS3Vol" datasource="billing-s3">
select /* *** ниже дублирование кода агрегации round ceil etc, обратить внимание при правке */
(sum(bucket_stat.usage_rgw_main_size_actual)/<cfqueryparam cfsqltype="cf_sql_integer" value=#hours#/>) as vol_B
,round(sum(bucket_stat.usage_rgw_main_size_actual)/<cfqueryparam cfsqltype="cf_sql_integer" value=#hours#/>/1024/1024/1024) as vol_GB
,greatest(round(sum(bucket_stat.usage_rgw_main_size_actual)/<cfqueryparam cfsqltype="cf_sql_integer" value=#hours#/>
/1024/1024/1024)-
case when bucket_stat.placement_id = 1 then 1 else 0 end, 0) as vol_GB_free_tier_substracted /*считается не в точности так, как в функции*/
,case
when bucket_stat.placement_id = 1 then 'paas.s3.ceph'
when bucket_stat.placement_id = 2 then 'paas.s3.cphc'
else 'unknown' end as code
--,bucket_stat.placement_id
,'WZ'||lpad(bucket_stat.owner, 5, '0') as wz -- *** здесь не число, а строка, поэтому другая формула обратной сборки WZ
from s3billing.bucket_stat
join s3billing.placement ON s3billing.placement.id=bucket_stat.placement_id
join s3billing.bucket_info ON bucket_info.id=bucket_stat.bucket_id
where bucket_stat.placement_id in (1,2)
AND bucket_stat.timestamp_addition >= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_start#/>
AND bucket_stat.timestamp_addition < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_finish#/>
group by bucket_stat.owner, bucket_stat.placement_id
order by bucket_stat.owner, bucket_stat.placement_id;
</cfquery>
<cfdump var=#qS3Vol#/>
<cfquery name="qS3OpsTrf" datasource="billing-s3">
select
sum(
CASE WHEN
(category.name LIKE 'get%'
OR category.name LIKE 'head%'
OR category.name LIKE 'options%'
) THEN ops ELSE 0 END
) as get
,ceil(sum(
CASE WHEN
(category.name LIKE 'get%'
OR category.name LIKE 'head%'
OR category.name LIKE 'options%'
) THEN ops ELSE 0 END
)/10000) as get_10k
,greatest(ceil(sum(
CASE WHEN
(category.name LIKE 'get%'
OR category.name LIKE 'head%'
OR category.name LIKE 'options%'
) THEN ops ELSE 0 END
)/10000) - CASE WHEN bucket_info.placement_id = 1 THEN 10 ELSE 0 END, 0
) as get_10k_free_tier_subtracted
,sum(
CASE WHEN
(category.name LIKE 'put%'
OR category.name LIKE 'post%'
OR category.name LIKE 'patch%'
OR category.name LIKE 'list%'
) THEN ops ELSE 0 END
) as put
,ceil(sum(
CASE WHEN
(category.name LIKE 'put%'
OR category.name LIKE 'post%'
OR category.name LIKE 'patch%'
OR category.name LIKE 'list%'
) THEN ops ELSE 0 END
)/10000) as put_10k
,greatest(ceil(sum(
CASE WHEN
(category.name LIKE 'put%'
OR category.name LIKE 'post%'
OR category.name LIKE 'patch%'
OR category.name LIKE 'list%'
) THEN ops ELSE 0 END
)/10000) - CASE WHEN bucket_info.placement_id = 1 THEN 1 ELSE 0 END, 0
) as put_10k_free_tier_subtracted
,(sum(bytes_sent)) as bytes_sent
,ceil(sum(bytes_sent)/1024/1024/1024) as bytes_sent_GB
,greatest(ceil(sum(bytes_sent)/1024/1024/1024) - CASE WHEN bucket_info.placement_id = 1 THEN 100 ELSE 0 END, 0
) as bytes_sent_GB_free_tier_subtracted
,case
when bucket_info.placement_id = 1 then 'paas.s3.ceph'
when bucket_info.placement_id = 2 then 'paas.s3.cphc'
else 'unknown' end as code
,bucket_info.placement_id
--category.name, bucket_info.name
,'WZ'||lpad(user_info.name, 5, '0') as wz
from s3billing.usage_bucket_by_user
join s3billing.user_info on usage_bucket_by_user.user_id=user_info.id
join s3billing.category on usage_bucket_by_user.category_id=category.id
join s3billing.bucket_info on usage_bucket_by_user.bucketid=bucket_info.id
join s3billing.placement on bucket_info.placement_id=placement.id
where 1=1
AND usage_bucket_by_user.time >= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_start#/>
AND usage_bucket_by_user.time < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_finish#/>
group by user_info.name, bucket_info.placement_id
order by user_info.name, bucket_info.placement_id;
</cfquery>
<cfdump var=#qS3OpsTrf#/>
<!--- В одном месте user_id int в другом owner varchar --->
<!--- Трафик хранится в той же таблице, что и остальной юзадж, можно было бы доставать в общем резалтсете
<!--- расчет запихнут в функцию. Неделю этим не занимался - забыл все совершенно --->
<cfquery name="qS3TrafficDefaultPlacement" datasource="billing-s3">
select sum(bytes_sent) as bytes,
--placement.name as placement,
case
when placement.name = 'COLD' then 'paas.s3.cphc'
when placement.name = 'default-placement' then 'paas.s3.ceph'
else 'unknown' end as code,
'WZ'||lpad(user_info.name, 5, '0') as wz
from s3billing.usage_bucket_by_user
join s3billing.user_info on usage_bucket_by_user.user_id=user_info.id
join s3billing.category on usage_bucket_by_user.category_id=category.id
join s3billing.bucket_info on usage_bucket_by_user.bucketid=bucket_info.id
join s3billing.placement on bucket_info.placement_id=placement.id
where 1=1
AND usage_bucket_by_user.time >= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_start#/>
AND usage_bucket_by_user.time < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_finish#/>
group by user_info.name, placement.name
order by user_info.name;
</cfquery>
<cfdump var=#qS3TrafficDefaultPlacement#/> --->
<!--- <cfquery name="qS3TrafficDefault" datasource="billing-s3">
select sum(bytes_sent) as bytes,
case
when placement.name = 'COLD' then 'paas.s3.cphc'
when placement.name = 'default-placement' then 'paas.s3.ceph'
else 'unknown' end as code,
'WZ'||lpad(user_info.name, 5, '0') as wz
from s3billing.usage_bucket_by_user
join s3billing.user_info on usage_bucket_by_user.user_id=user_info.id
join s3billing.category on usage_bucket_by_user.category_id=category.id
join s3billing.bucket_info on usage_bucket_by_user.bucketid=bucket_info.id
join s3billing.placement on bucket_info.placement_id=placement.id AND placement.name='default-placement'
where s3billing.usage_bucket_by_user.bucketid='0'
AND usage_bucket_by_user.time >= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_start#/>
AND usage_bucket_by_user.time < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_finish#/>
group by user_info.name
order by user_info.name;
</cfquery>
<cfdump var=#qS3TrafficDefault#/> --->
<!---
задача (вызванная сыростью базы биллинга)
смапить код параметра с VDC (1:n)
iaas.ngc.i31.ram-m
iaas.ngc.a28.ram-m
cl01:
7 хостов Lenovo ThinkSystem SR650 -[7X06CTO1WW]-
2 процессора Xeon(R) Gold 6226R 16 ядер 32 потока каждый 2.9 ГГц
1.25тб озу в каждом.
В 4 из 7 есть по 4 GPU NVIDIA A16 16GB в каждом.
cl01-vsan:
16 хостов Lenovo ThinkSystem SR650 -[7X06CTO1WW]-
2 процессора Xeon(R) Gold 6226R 16 ядер 32 потока каждый 2.9 ГГц
1.25тб озу в каждом.
В 9 из 16 есть по 4 GPU NVIDIA A16 16GB в каждом.
cl02:
10 Huawei 2488H V5
4 процессора Xeon(R) Gold 6254 18 ядер 36 потоков каждый. 3.1 ГГц
2тб озу в каждом.
5 Huawei Atlas 800 (Model 3010)
2 процессора Xeon(R) Gold 6254 18 ядер 36 потоков каждый. 3.1 ГГц
1.5тб озу в каждом.
cl04-vsan:
10 Apex AR320-12
2 процессора AMD EPYC 7543 32 ядра 64 потока каждый. 2.8 ГГц
2тб озу в каждом.
18 Apex AR320-12-E7543
2 процессора AMD EPYC 7543 32 ядра 64 потока каждый. 2.8 ГГц
2тб озу в каждом.
cl05-1c:
1 Asus RS720A-E12-RS24U
2 процессора AMD EPYC 9274F 24 ядра 48 потоков каждый. 4.05 ГГц
1тб озу.
7 ручная сборка
MB Asus ProArt B650-Creator
Процессор AMD Ryzen 9 7950X 16 ядер 32 потока каждый. 4.5 ГГц
192гб озу каждый.
1 ручная сборка
процессор AMD Ryzen Threadripper PRO 5995WX 64 ядра 128 потоков каждый. 2.7 ГГц
512гб озу.
cl06-vsan:
15 R320
2 процессора Xeon(R) Gold 6342 24 ядра 48 потоков каждый. 2.8 ГГц
1тб озу каждый.
Xeon(R) Gold 6226R 2.9 ГГц
Xeon(R) Gold 6254 3.1 ГГц
AMD EPYC 7543 2.8 ГГц
AMD EPYC 9274F 4.05 ГГц
AMD Ryzen 9 7950X 4.5 ГГц
AMD Ryzen Threadripper PRO 5995WX 2.7 ГГц
Xeon(R) Gold 6342 2.8 ГГц --->
<!--- 2025-08-15 20:47:44 *** Операции S3 считаются не так, как написано в тарифе. Например, считается list. В тарифе вообще не описан минимальный лимит --->
<!--- BEGIN
RETURN QUERY
(
select
billing_per_user_fix_pl.placement as placement,
(CASE
WHEN ( billing_per_user_fix_pl.placement = 'HOT'
) THEN greatest(ceil(sum(size)/1024/1024/1024)-1,0)
WHEN ( not billing_per_user_fix_pl.placement = 'HOT'
) THEN ceil(sum(size)/1024/1024/1024)
END) AS size_GB,
(CASE
WHEN ( billing_per_user_fix_pl.placement = 'HOT'
) THEN greatest(ceil(sum(get)/10000)-10,0)
WHEN ( not billing_per_user_fix_pl.placement = 'HOT'
) THEN ceil(sum(get)/10000)
END) AS get_10k,
(CASE
WHEN ( billing_per_user_fix_pl.placement = 'HOT'
) THEN greatest(ceil(sum(put)/10000)-1,0)
WHEN ( not billing_per_user_fix_pl.placement = 'HOT'
) THEN ceil(sum(put)/10000)
END) AS put_10k,
(CASE
WHEN ( billing_per_user_fix_pl.placement = 'HOT'
) then greatest(ceil(sum(bytes_sent)/1024/1024/1024)-100,0)
WHEN ( not billing_per_user_fix_pl.placement = 'HOT'
) THEN ceil(sum(bytes_sent)/1024/1024/1024)
END) AS bytes_sent_GB
from s3billing.billing_per_user_fix_pl(_ds,_df,_user)
group by billing_per_user_fix_pl.placement
UNION all
select
'HOT_FREE_LIMIT' as placement,
'1' AS size_GB,
'10' AS get_10k,
'1' AS put_10k,
'100' AS bytes_sent_GB
);
END; --->
<!---
BEGIN
RETURN QUERY
SELECT
s3billing.bucket_info.name AS bucket_name,
(case
when ( s3billing.placement.name = 'default-placement') then 'HOT'
WHEN ( not s3billing.placement.name = 'default-placement' ) THEN s3billing.placement.name
end
) as placement,
coalesce(round(sum(usage_rgw_main_size_actual)/
(SELECT (DATE_PART('day',
((TO_TIMESTAMP(_df, 'YYYY-MM-DD HH24:MI:SS'))
-TO_TIMESTAMP(_ds, 'YYYY-MM-DD HH24:MI:SS'))
)*24+
DATE_PART('hour',
((TO_TIMESTAMP(_df, 'YYYY-MM-DD HH24:MI:SS'))
-TO_TIMESTAMP(_ds, 'YYYY-MM-DD HH24:MI:SS'))
)))
)::numeric,0) AS size
,coalesce(s2.get, 0) AS get
,coalesce(s2.put, 0) AS put
,coalesce(s2.bytes_sent, 0) as bytes_sent
FROM s3billing.bucket_stat
INNER JOIN s3billing.placement ON s3billing.bucket_stat.placement_id=s3billing.placement.id
INNER JOIN s3billing.bucket_info ON s3billing.bucket_stat.bucket_id=s3billing.bucket_info.id
LEFT JOIN (
SELECT
s1.bucket_id AS bucket_id
,s1.bucket_name AS bucket_name,
(case
when ( s1.placement = 'default-placement') then 'HOT'
WHEN ( not s1.placement = 'default-placement' ) THEN s1.placement
end
) as placement
,coalesce(sum(s1.get) ,0) AS get
,coalesce(sum(s1.put) ,0) AS put
,coalesce(sum(s1.bytes_sent), 0) AS bytes_sent
FROM (
SELECT
s3billing.bucket_info.id AS bucket_id
,s3billing.bucket_info.name AS bucket_name
,(case
when ( s3billing.placement.name = 'default-placement') then 'HOT'
WHEN ( not s3billing.placement.name = 'default-placement' ) THEN s3billing.placement.name
end
) as placement
,(CASE
WHEN ( s3billing.category.name LIKE 'get%'
OR s3billing.category.name LIKE 'head%'
OR s3billing.category.name LIKE 'options%'
) THEN coalesce(sum(ops), 0)
END) AS get
,(CASE
WHEN ( s3billing.category.name LIKE 'put%'
OR s3billing.category.name LIKE 'post%'
OR s3billing.category.name LIKE 'patch%'
OR s3billing.category.name LIKE 'list%'
) THEN coalesce(sum(ops), 0)
END) AS put
,coalesce(sum(usage_bucket_by_user.bytes_sent), 0) AS bytes_sent
FROM
s3billing.usage_bucket_by_user
INNER JOIN s3billing.bucket_info ON s3billing.usage_bucket_by_user.bucketid = s3billing.bucket_info.id
INNER JOIN s3billing.placement ON s3billing.bucket_info.placement_id = s3billing.placement.id
INNER JOIN s3billing.user_info ON s3billing.usage_bucket_by_user.user_id = s3billing.user_info.id
INNER JOIN s3billing.category ON s3billing.usage_bucket_by_user.category_id = s3billing.category.id
WHERE
s3billing.user_info.name=_user
AND s3billing.usage_bucket_by_user.time >=TO_TIMESTAMP(_ds, 'YYYY-MM-DD HH24:MI:SS')
AND s3billing.usage_bucket_by_user.time < TO_TIMESTAMP(_df, 'YYYY-MM-DD HH24:MI:SS')
GROUP BY
s3billing.bucket_info.name
,s3billing.placement.name
,s3billing.category.name
,s3billing.bucket_info.id
) AS s1
GROUP BY
s1.bucket_name
,s1.bucket_id
,s1.placement
ORDER BY
s1.placement
,s1.bucket_name
) AS s2 ON s2.bucket_id = s3billing.bucket_stat.bucket_id
WHERE owner=_user
AND timestamp_addition >= TO_TIMESTAMP(_ds, 'YYYY-MM-DD HH24:MI:SS')
AND timestamp_addition < TO_TIMESTAMP(_df, 'YYYY-MM-DD HH24:MI:SS')
GROUP BY
s3billing.bucket_info.name
,s3billing.placement.name
,s3billing.bucket_stat.bucket_id
,s2.get
,s2.put
,s2.bytes_sent
ORDER BY
s3billing.placement.name
,s3billing.bucket_info.name
;
END; --->
<!--- select * from s3billing.billing_per_user_fix_pl('2025-05-01 00:00:00','2025-06-01 00:00:00','1395'); --->
+456
View File
@@ -0,0 +1,456 @@
<cfset dt_finish=createDateTime(year(Now()),month(Now()),1,0,0,0)/>
<cfset dt_start=dateAdd('m',-1,dt_finish)/>
<cfset hours=dateDiff('h',dt_start,dt_finish)/>
Внимание! округление вверх при расчете метрик
<cfdump var=#dt_start#/>
<cfdump var=#dt_finish#/>
<cfdump var=#hours#/>
<!--- Нужно еще применить политики бесплатного минимума --->
<cfquery name="qCode" datasource="dwh">
select distinct p.code
from elma.deals d
join elma.deals_services siv on (d.__id=ANY(siv.deal))
join elma.service_parametrs p on (p.__id = ANY(siv.params))
join elma.companies k on (d._companies=k.__id)
join elma.additional_agreements aa on (aa.__id = ANY(siv.additional_agreement))
join elma.aggrements a on (aa.contract_uid = a.__id)
where p.type=3 AND aa.is_actual
order by p.code
</cfquery>
<!--- <cfdump var=#qCode#/> --->
<cfquery name="qSpec" datasource="dwh">
select k.id_klienta as wz, p.code, p.price, p.discount, k.__name as contragent, a.__name as contract, d.__name as deal, siv.abstractive_service as abstract_service, siv.modifier, siv.user_description
,p.__name as metric, p.ed_izm
--, aa.is_actual
from elma.deals d
join elma.deals_services siv on (d.__id=ANY(siv.deal))
join elma.service_parametrs p on (p.__id = ANY(siv.params))
join elma.companies k on (d._companies=k.__id)
join elma.additional_agreements aa on (aa.__id = ANY(siv.additional_agreement))
join elma.aggrements a on (aa.contract_uid = a.__id)
where p.type=3 AND aa.is_actual
order by k.id_klienta, p.code
</cfquery>
<!--- здесь имеем список кодов с ценами и WZ. Каждому коду можно поставить в соответствие запрос, который даст по нему выборку. Изредка один запрос может вывести 2 кода, но разбить на 2 запроса легко. Кроме того, запросы можно объединить через union в один - может быть, так будет лучше читаться (быстрее выполняться не будет) --->
<cfdump var=#qSpec#/>
<cfquery name="qComputing" datasource="billing-vc">
select 'WZ'||to_char(tenant.wzcode,'FM00000') as wz, vdc.name as vdc_name,
case
when vdc.name like '%-v1cl1%' then 'iaas.ngc.i29'
when vdc.name like '%-v1cl2%' then 'iaas.ngc.i31'
when vdc.name like '%-v1cl4%' then 'iaas.ngc.a28'
when vdc.name like '%-v1cl6%' then 'iaas.ngc.i28'
else '['||vdc.name||']' end as code,
sum(cpu_used/cpu_speed)/4. as core_h,
sum(mem_used)/1024/4. as gb_h
from ngcloud_ru.capacity_resource
join ngcloud_ru.vdc on capacity_resource.vdc_id=vdc.id
join ngcloud_ru.tenant on tenant.id=vdc.tenant_id
where tenant.wzcode > 0
AND capacity_resource.timestamp >= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_start#/>
AND capacity_resource.timestamp < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_finish#/>
group by tenant.wzcode, vdc.name
order by tenant.wzcode, vdc.name;
</cfquery>
<!--- <cfdump var=#qComputing#/> --->
<!--- переделать storage_profile_types с расшифровкой ssd, sata, можно прямо до каталожного кода --->
<cfquery name="qStorage" datasource="billing-vc">
select 'WZ'||to_char(tenant.wzcode,'FM00000') as wz, vdc.name as vdc_name,
case
WHEN vdc.name LIKE '%-v1cl1%' THEN 'iaas.ngc.i29'
WHEN vdc.name LIKE '%-v1cl2%' THEN 'iaas.ngc.i31'
WHEN vdc.name LIKE '%-v1cl4%' THEN 'iaas.ngc.a28'
WHEN vdc.name LIKE '%-v1cl6%' THEN 'iaas.ngc.i28'
ELSE '['||vdc.name||']' END
|| CASE
WHEN storage_profile_types.name ILIKE '%-SSD%' THEN '.ssd-m'
WHEN storage_profile_types.name ILIKE '%-SAS' THEN '.sas-m'
WHEN storage_profile_types.name ILIKE '%-SATA' THEN '.sata-m'
ELSE '.['|| storage_profile_types.name ||']' END
as code,
storage_profile_types.name, -- *** это не тип, а профайл
sum("limit")/1024./4 as gb_h_limit, -- 4 потому, что сбор раз в 15 минут
sum(used)/1024./4 as gb_h_used
from ngcloud_ru.capacity_storage
join ngcloud_ru.vdc on capacity_storage.vdc_id=vdc.id
join ngcloud_ru.tenant on tenant.id=vdc.tenant_id
join ngcloud_ru.storage_profile_types on capacity_storage.storage_profile_types_id=storage_profile_types.id
where tenant.wzcode > 0
AND capacity_storage.timestamp >= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_start#/>
AND capacity_storage.timestamp < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_finish#/>
group by tenant.wzcode, vdc.name, storage_profile_types.name
order by tenant.wzcode, vdc.name, storage_profile_types.name;
</cfquery>
<!--- <cfdump var=#qStorage#/> --->
<!---
"placement" "size_gb" "get_10k" "put_10k" "bytes_sent_gb"
HOT_FREE_LIMIT 1 10 1 100
--->
<!--- надо дисконтировать не ГБ-часы а ГБ-месяцы --->
<cfquery name="qS3Vol" datasource="billing-s3">
select /* *** ниже дублирование кода агрегации - round ceil etc, обратить внимание при правке */
(sum(bucket_stat.usage_rgw_main_size_actual)/<cfqueryparam cfsqltype="cf_sql_integer" value=#hours#/>) as vol_B
,round(sum(bucket_stat.usage_rgw_main_size_actual)/<cfqueryparam cfsqltype="cf_sql_integer" value=#hours#/>/1024/1024/1024) as vol_GB
,greatest(round(sum(bucket_stat.usage_rgw_main_size_actual)/<cfqueryparam cfsqltype="cf_sql_integer" value=#hours#/>
/1024/1024/1024)-
case when bucket_stat.placement_id = 1 then 1 else 0 end, 0) as vol_GB_free_tier_subtracted /*считается не в точности так, как в функции*/
,case
when bucket_stat.placement_id = 1 then 'paas.s3.ceph'
when bucket_stat.placement_id = 2 then 'paas.s3.cphc'
else '['|| TO_CHAR(bucket_stat.placement_id,'FM9') ||']' end as code
--,bucket_stat.placement_id
,'WZ'||lpad(bucket_stat.owner, 5, '0') as wz -- *** здесь не число, а строка, поэтому другая формула обратной сборки WZ
from s3billing.bucket_stat
join s3billing.placement ON s3billing.placement.id=bucket_stat.placement_id
join s3billing.bucket_info ON bucket_info.id=bucket_stat.bucket_id
where bucket_stat.placement_id in (1,2)
AND bucket_stat.timestamp_addition >= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_start#/>
AND bucket_stat.timestamp_addition < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_finish#/>
group by bucket_stat.owner, bucket_stat.placement_id
order by bucket_stat.owner, bucket_stat.placement_id;
</cfquery>
<!--- <cfdump var=#qS3Vol#/> --->
<cfquery name="qS3OpsTrf" datasource="billing-s3">
select
sum(
CASE WHEN
(category.name LIKE 'get%'
OR category.name LIKE 'head%'
OR category.name LIKE 'options%'
) THEN ops ELSE 0 END
) as get
,ceil(sum(
CASE WHEN
(category.name LIKE 'get%'
OR category.name LIKE 'head%'
OR category.name LIKE 'options%'
) THEN ops ELSE 0 END
)/10000) as get_10k
,greatest(ceil(sum(
CASE WHEN
(category.name LIKE 'get%'
OR category.name LIKE 'head%'
OR category.name LIKE 'options%'
) THEN ops ELSE 0 END
)/10000) - CASE WHEN bucket_info.placement_id = 1 THEN 10 ELSE 0 END, 0
) as get_10k_free_tier_subtracted
,sum(
CASE WHEN
(category.name LIKE 'put%'
OR category.name LIKE 'post%'
OR category.name LIKE 'patch%'
OR category.name LIKE 'list%'
) THEN ops ELSE 0 END
) as put
,ceil(sum(
CASE WHEN
(category.name LIKE 'put%'
OR category.name LIKE 'post%'
OR category.name LIKE 'patch%'
OR category.name LIKE 'list%'
) THEN ops ELSE 0 END
)/10000) as put_10k
,greatest(ceil(sum(
CASE WHEN
(category.name LIKE 'put%'
OR category.name LIKE 'post%'
OR category.name LIKE 'patch%'
OR category.name LIKE 'list%'
) THEN ops ELSE 0 END
)/10000) - CASE WHEN bucket_info.placement_id = 1 THEN 1 ELSE 0 END, 0
) as put_10k_free_tier_subtracted
,(sum(bytes_sent)) as bytes_sent
,ceil(sum(bytes_sent)/1024/1024/1024) as bytes_sent_GB
,greatest(ceil(sum(bytes_sent)/1024/1024/1024) - CASE WHEN bucket_info.placement_id = 1 THEN 100 ELSE 0 END, 0
) as bytes_sent_GB_free_tier_subtracted
,case
when bucket_info.placement_id = 1 then 'paas.s3.ceph'
when bucket_info.placement_id = 2 then 'paas.s3.cphc'
else '['|| TO_CHAR(bucket_info.placement_id,'FM9') ||']' end as code --*** зачем делать там ключ bigint
,bucket_info.placement_id
--category.name, bucket_info.name
,'WZ'||lpad(user_info.name, 5, '0') as wz
from s3billing.usage_bucket_by_user
join s3billing.user_info on usage_bucket_by_user.user_id=user_info.id
join s3billing.category on usage_bucket_by_user.category_id=category.id
join s3billing.bucket_info on usage_bucket_by_user.bucketid=bucket_info.id
join s3billing.placement on bucket_info.placement_id=placement.id
where 1=1
AND usage_bucket_by_user.time >= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_start#/>
AND usage_bucket_by_user.time < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_finish#/>
group by user_info.name, bucket_info.placement_id
order by user_info.name, bucket_info.placement_id;
</cfquery>
<!--- <cfdump var=#qS3OpsTrf#/> --->
<cfquery name="qUnifiedMetric" dbType="query">
select wz, code || '.cpu-m' as code, core_h as raw_metric, core_h as metric, core_h as chargeable_metric from qComputing
union all
select wz, code || '.ram-m' as code, gb_h as raw_metric, gb_h as metric, gb_h as chargeable_metric from qComputing
union all
select wz, code, gb_h_used as raw_metric, gb_h_used as metric, gb_h_used as chargeable_metric from qStorage
union all
select wz, code || '.vol', vol_b as raw_metric, vol_gb as metric, vol_GB_free_tier_subtracted as chargeable_metric from qS3Vol
union all
select wz, code || '.get', get as raw_metric, get_10k as metric, get_10k_free_tier_subtracted as chargeable_metric from qS3OpsTrf
union all
select wz, code || '.put', put as raw_metric, put_10k as metric, put_10k_free_tier_subtracted as chargeable_metric from qS3OpsTrf
union all
select wz, code || '.trf', bytes_sent as raw_metric, bytes_sent_gb as metric, bytes_sent_gb_free_tier_subtracted as chargeable_metric from qS3OpsTrf
</cfquery>
<cfdump var=#qUnifiedMetric#/>
<cfquery name="qCharge" dbType="query">
SELECT
wz
,code
,price
,discount
,contragent
,contract
,deal
,abstract_service
,modifier
,user_description
,ed_izm
FROM qSpec as s, qUnifiedMetric as m WHERE s.wz=m.wz AND s.code=m.code
</cfquery>
<!--- looks like QoQ does not support join syntax, at least of Lucee 5.4--->
<cfdump var=#qCharge#/>
<!---
--->
<!--- --,m.*
--,s.price*(100-s.discount)/100 as discounted_price
--,s.price*(100-s.discount)/100*m.chargeable_metric as charge --->
<!--- В одном месте user_id int в другом owner varchar --->
<!---
задача (вызванная сыростью базы биллинга)
смапить код параметра с VDC (1:n)
iaas.ngc.i31.ram-m
iaas.ngc.a28.ram-m
cl01:
7 хостов Lenovo ThinkSystem SR650 -[7X06CTO1WW]-
2 процессора Xeon(R) Gold 6226R 16 ядер 32 потока каждый 2.9 ГГц
1.25тб озу в каждом.
В 4 из 7 есть по 4 GPU NVIDIA A16 16GB в каждом.
cl01-vsan:
16 хостов Lenovo ThinkSystem SR650 -[7X06CTO1WW]-
2 процессора Xeon(R) Gold 6226R 16 ядер 32 потока каждый 2.9 ГГц
1.25тб озу в каждом.
В 9 из 16 есть по 4 GPU NVIDIA A16 16GB в каждом.
cl02:
10 Huawei 2488H V5
4 процессора Xeon(R) Gold 6254 18 ядер 36 потоков каждый. 3.1 ГГц
2тб озу в каждом.
5 Huawei Atlas 800 (Model 3010)
2 процессора Xeon(R) Gold 6254 18 ядер 36 потоков каждый. 3.1 ГГц
1.5тб озу в каждом.
cl04-vsan:
10 Apex AR320-12
2 процессора AMD EPYC 7543 32 ядра 64 потока каждый. 2.8 ГГц
2тб озу в каждом.
18 Apex AR320-12-E7543
2 процессора AMD EPYC 7543 32 ядра 64 потока каждый. 2.8 ГГц
2тб озу в каждом.
cl05-1c:
1 Asus RS720A-E12-RS24U
2 процессора AMD EPYC 9274F 24 ядра 48 потоков каждый. 4.05 ГГц
1тб озу.
7 ручная сборка
MB Asus ProArt B650-Creator
Процессор AMD Ryzen 9 7950X 16 ядер 32 потока каждый. 4.5 ГГц
192гб озу каждый.
1 ручная сборка
процессор AMD Ryzen Threadripper PRO 5995WX 64 ядра 128 потоков каждый. 2.7 ГГц
512гб озу.
cl06-vsan:
15 R320
2 процессора Xeon(R) Gold 6342 24 ядра 48 потоков каждый. 2.8 ГГц
1тб озу каждый.
Xeon(R) Gold 6226R 2.9 ГГц
Xeon(R) Gold 6254 3.1 ГГц
AMD EPYC 7543 2.8 ГГц
AMD EPYC 9274F 4.05 ГГц
AMD Ryzen 9 7950X 4.5 ГГц
AMD Ryzen Threadripper PRO 5995WX 2.7 ГГц
Xeon(R) Gold 6342 2.8 ГГц --->
<!--- 2025-08-15 20:47:44 *** Операции S3 считаются не так, как написано в тарифе. Например, считается list. В тарифе вообще не описан минимальный лимит --->
<!--- BEGIN
RETURN QUERY
(
select
billing_per_user_fix_pl.placement as placement,
(CASE
WHEN ( billing_per_user_fix_pl.placement = 'HOT'
) THEN greatest(ceil(sum(size)/1024/1024/1024)-1,0)
WHEN ( not billing_per_user_fix_pl.placement = 'HOT'
) THEN ceil(sum(size)/1024/1024/1024)
END) AS size_GB,
(CASE
WHEN ( billing_per_user_fix_pl.placement = 'HOT'
) THEN greatest(ceil(sum(get)/10000)-10,0)
WHEN ( not billing_per_user_fix_pl.placement = 'HOT'
) THEN ceil(sum(get)/10000)
END) AS get_10k,
(CASE
WHEN ( billing_per_user_fix_pl.placement = 'HOT'
) THEN greatest(ceil(sum(put)/10000)-1,0)
WHEN ( not billing_per_user_fix_pl.placement = 'HOT'
) THEN ceil(sum(put)/10000)
END) AS put_10k,
(CASE
WHEN ( billing_per_user_fix_pl.placement = 'HOT'
) then greatest(ceil(sum(bytes_sent)/1024/1024/1024)-100,0)
WHEN ( not billing_per_user_fix_pl.placement = 'HOT'
) THEN ceil(sum(bytes_sent)/1024/1024/1024)
END) AS bytes_sent_GB
from s3billing.billing_per_user_fix_pl(_ds,_df,_user)
group by billing_per_user_fix_pl.placement
UNION all
select
'HOT_FREE_LIMIT' as placement,
'1' AS size_GB,
'10' AS get_10k,
'1' AS put_10k,
'100' AS bytes_sent_GB
);
END; --->
<!---
BEGIN
RETURN QUERY
SELECT
s3billing.bucket_info.name AS bucket_name,
(case
when ( s3billing.placement.name = 'default-placement') then 'HOT'
WHEN ( not s3billing.placement.name = 'default-placement' ) THEN s3billing.placement.name
end
) as placement,
coalesce(round(sum(usage_rgw_main_size_actual)/
(SELECT (DATE_PART('day',
((TO_TIMESTAMP(_df, 'YYYY-MM-DD HH24:MI:SS'))
-TO_TIMESTAMP(_ds, 'YYYY-MM-DD HH24:MI:SS'))
)*24+
DATE_PART('hour',
((TO_TIMESTAMP(_df, 'YYYY-MM-DD HH24:MI:SS'))
-TO_TIMESTAMP(_ds, 'YYYY-MM-DD HH24:MI:SS'))
)))
)::numeric,0) AS size
,coalesce(s2.get, 0) AS get
,coalesce(s2.put, 0) AS put
,coalesce(s2.bytes_sent, 0) as bytes_sent
FROM s3billing.bucket_stat
INNER JOIN s3billing.placement ON s3billing.bucket_stat.placement_id=s3billing.placement.id
INNER JOIN s3billing.bucket_info ON s3billing.bucket_stat.bucket_id=s3billing.bucket_info.id
LEFT JOIN (
SELECT
s1.bucket_id AS bucket_id
,s1.bucket_name AS bucket_name,
(case
when ( s1.placement = 'default-placement') then 'HOT'
WHEN ( not s1.placement = 'default-placement' ) THEN s1.placement
end
) as placement
,coalesce(sum(s1.get) ,0) AS get
,coalesce(sum(s1.put) ,0) AS put
,coalesce(sum(s1.bytes_sent), 0) AS bytes_sent
FROM (
SELECT
s3billing.bucket_info.id AS bucket_id
,s3billing.bucket_info.name AS bucket_name
,(case
when ( s3billing.placement.name = 'default-placement') then 'HOT'
WHEN ( not s3billing.placement.name = 'default-placement' ) THEN s3billing.placement.name
end
) as placement
,(CASE
WHEN ( s3billing.category.name LIKE 'get%'
OR s3billing.category.name LIKE 'head%'
OR s3billing.category.name LIKE 'options%'
) THEN coalesce(sum(ops), 0)
END) AS get
,(CASE
WHEN ( s3billing.category.name LIKE 'put%'
OR s3billing.category.name LIKE 'post%'
OR s3billing.category.name LIKE 'patch%'
OR s3billing.category.name LIKE 'list%'
) THEN coalesce(sum(ops), 0)
END) AS put
,coalesce(sum(usage_bucket_by_user.bytes_sent), 0) AS bytes_sent
FROM
s3billing.usage_bucket_by_user
INNER JOIN s3billing.bucket_info ON s3billing.usage_bucket_by_user.bucketid = s3billing.bucket_info.id
INNER JOIN s3billing.placement ON s3billing.bucket_info.placement_id = s3billing.placement.id
INNER JOIN s3billing.user_info ON s3billing.usage_bucket_by_user.user_id = s3billing.user_info.id
INNER JOIN s3billing.category ON s3billing.usage_bucket_by_user.category_id = s3billing.category.id
WHERE
s3billing.user_info.name=_user
AND s3billing.usage_bucket_by_user.time >=TO_TIMESTAMP(_ds, 'YYYY-MM-DD HH24:MI:SS')
AND s3billing.usage_bucket_by_user.time < TO_TIMESTAMP(_df, 'YYYY-MM-DD HH24:MI:SS')
GROUP BY
s3billing.bucket_info.name
,s3billing.placement.name
,s3billing.category.name
,s3billing.bucket_info.id
) AS s1
GROUP BY
s1.bucket_name
,s1.bucket_id
,s1.placement
ORDER BY
s1.placement
,s1.bucket_name
) AS s2 ON s2.bucket_id = s3billing.bucket_stat.bucket_id
WHERE owner=_user
AND timestamp_addition >= TO_TIMESTAMP(_ds, 'YYYY-MM-DD HH24:MI:SS')
AND timestamp_addition < TO_TIMESTAMP(_df, 'YYYY-MM-DD HH24:MI:SS')
GROUP BY
s3billing.bucket_info.name
,s3billing.placement.name
,s3billing.bucket_stat.bucket_id
,s2.get
,s2.put
,s2.bytes_sent
ORDER BY
s3billing.placement.name
,s3billing.bucket_info.name
;
END; --->
<!--- select * from s3billing.billing_per_user_fix_pl('2025-05-01 00:00:00','2025-06-01 00:00:00','1395'); --->
+33
View File
@@ -0,0 +1,33 @@
<cfsilent>
<!---Замещает любую переменную (*** небезопасно) тега layout:page --->
<!---Тег layout:page проглатывает собственный контент, и вместо него после закрытия выводит разметку на основании атрибутов (при открытии тега он формирует переменные - фрагменты разметки - по шаблону) и вложенных тегов layout:attribute (которые по закрытии тега на самом деле перезаписывают переменные в layout:page).
Вложенные теги удобны, чтобы передавать читабельную разметку, а не строку в кавычках.--->
<cfparam name="ATTRIBUTES.name"/><!---имя переменной layout:page, чаще всего title, controls--->
<!--- ATTRIBUTES.value --->
<cfparam name="ATTRIBUTES.append" default=""/><!---before,after--->
<cfif thisTag.executionMode IS "end">
<cfassociate basetag="cf_page"/>
<cfset layoutTemplate=getBaseTagData('cf_page',1)/>
<cfif structKeyExists(ATTRIBUTES, "value")>
<cfset value=ATTRIBUTES.value/>
<cfelse>
<cfset value=thisTag.generatedContent/>
</cfif>
<!---ниже в комментариях предполагается, что мы меняем фрагмент разметки, например, controls, но на самом деле это может быть любая переменная тега layout:page--->
<cfif structKeyExists(layoutTemplate,"#ATTRIBUTES.name#") AND lcase(ATTRIBUTES.append) EQ "before">
<!---дописать в начало фрагмента разметки с именем name, сгенерированного layout:page, например, controls--->
<cfset "layoutTemplate.#ATTRIBUTES.name#" = value & layoutTemplate["#ATTRIBUTES.name#"]/>
<cfelseif structKeyExists(layoutTemplate,"#ATTRIBUTES.name#") AND lcase(ATTRIBUTES.append) EQ "after">
<!---дописать в конец фрагмента разметки с именем name,, сгенерированного layout:page, например, controls--->
<cfset "layoutTemplate.#ATTRIBUTES.name#" = layoutTemplate["#ATTRIBUTES.name#"] & value/>
<cfelse>
<!---заменить фрагмент разметки с именем name, сгенерированный layout:page--->
<cfset "layoutTemplate.#ATTRIBUTES.name#"= value/>
</cfif>
<cfset thisTag.generatedContent=""/>
</cfif>
</cfsilent>
+43
View File
@@ -0,0 +1,43 @@
<cfsilent>
<cfimport prefix="m" taglib="../lib"/>
<cfimport prefix="c" taglib="../lib/controls"/>
<!---*** идея включить титул в метаданные была не совсем пустой, но когда титул определяется в селекте, это не слишком удобно --->
<cfassociate basetag="cf_grid_head" datacollection="headersArray"/>
<cfset envelope=getBaseTagData('cf_grid_head',1)/>
<cfparam name="ATTRIBUTES.title" type="string" default="#envelope.ATTRIBUTES.titleMap[ATTRIBUTES.name].title#"/>
<cfparam name="ATTRIBUTES.name" type="string"/><!--- Заголовок указвается на том поле, по которому будет сортировка, а не на том, которе отображается --->
<cfparam name="ATTRIBUTES.arrows" type="boolean" default="Yes"/>
<cfset attributeList="name,arrows,title"/>
<!--- В данном случае реализован подход: дополнительные атрибуты передаются вниз.
Другой вариант - создавать атрибут extra, в который писать суффикс QueryString.
Первый подход, использованный здесь, позволяет иметь доступ к дополнительным атрибутам, но непонятно, зачем - ведь их имена все равно неизвестны.
Очевидный минус этого подхода - возможный конфликт имен с именами существующих атрибутов --->
<cfset extraAttributes=structNew()/>
<!--- дополнительные атрибуты родительского тега--->
<cfif StructKeyExists(envelope, "extraAttributes") AND isStruct(envelope.extraAttributes)>
<cfloop collection=#envelope.extraAttributes# item="attr">
<cfif NOT listFindNoCase(attributeList, attr)><!--- проверка относительно локальных атрибутов, чтобы их не перетереть--->
<cfset val="#structFind(envelope.extraAttributes, attr)#"/>
<cfif IsSimpleValue(val)>
<cfset structInsert(extraAttributes, attr, val)/>
</cfif>
</cfif>
</cfloop>
</cfif>
<cfloop collection=#ATTRIBUTES# item="attr">
<cfif NOT listFindNoCase(attributeList, attr)>
<cfset val="#structFind(ATTRIBUTES, attr)#"/>
<cfif IsSimpleValue(val)>
<cfset structInsert(extraAttributes, attr, val, "Yes")/><!--- локальные атрибуты перетрут родительские --->
</cfif>
</cfif>
</cfloop>
</cfsilent><cfif thisTag.executionMode is "end"><cfoutput>#ATTRIBUTES.title#
<cfif ATTRIBUTES.arrows><c:order_arrows sortArray=#envelope.ATTRIBUTES.sortArray# n=#envelope.ATTRIBUTES.titleMap[ATTRIBUTES.name].ordinal# attributeCollection=#extraAttributes#/></cfif></cfoutput></cfif>
+10
View File
@@ -0,0 +1,10 @@
<!--- It is strongly recommended to keep this tag closed. Unclosed tag generates output into the variable ATTRIBUTES.output only, which may be confusing --->
<cfif thisTag.executionMode IS "end" OR NOT thisTag.hasEndTag>
<cfparam name="ATTRIBUTES.backUrl" type="string" default="."/>
<cfparam name="ATTRIBUTES.enable" type="boolean" default="No"/>
<cfoutput>
<button type="submit" name="save" class="maincontrol"<cfif NOT ATTRIBUTES.enable> disabled</cfif>>#request.i18("Сохранить","Save")#</button>
<button type="submit" name="saveAndClose" class="maincontrol"<cfif NOT ATTRIBUTES.enable> disabled</cfif>>#request.i18("Сохранить и закрыть","Save and Close")#</button>
<button type="button" name="close" class="maincontrol" onClick="document.location.href='#ATTRIBUTES.backUrl#'">#request.i18("Закрыть","Close")#</button>
</cfoutput>
</cfif>
+10
View File
@@ -0,0 +1,10 @@
<cfsilent>
<cfparam name="ATTRIBUTES.title" default=""/>
<!---
<cfset var content=thisTag.generagedContent/>
--->
</cfsilent><!---
---><cfif thisTag.executionMode is "start"><div class="tr">
<div class="th"><cfoutput>#ATTRIBUTES.title#</cfoutput></div><div class="td">
<cfelseif thisTag.executionMode is "end"></div></div></cfif>
+8
View File
@@ -0,0 +1,8 @@
<!--- It is strongly recommended to keep this tag closed. Unclosed tag generates output into the variable ATTRIBUTES.output only, which may be confusing --->
<cfif thisTag.executionMode IS "end" OR NOT thisTag.hasEndTag>
<cfparam name="ATTRIBUTES.backUrl" type="string" default=""/>
<cfoutput>
<button type="submit" name="saveAndClose" class="maincontrol">#request.i18("Применить","Apply")#</button>
<button type="submit" name="resetAndClose" class="maincontrol">#request.i18("Снять","Reset")#</button>
<button type="button" name="close" onClick="document.location.href='#ATTRIBUTES.backUrl#'" class="maincontrol">#request.i18("Закрыть","Close")#</button></cfoutput>
</cfif>
+24
View File
@@ -0,0 +1,24 @@
<!--- It is strongly recommended to keep this tag closed. Unclosed tag generates output into the variable ATTRIBUTES.output only, which may be confusing --->
<!---v0.2 10:07 02.01.2019 - skipped url params--->
<cfif thisTag.executionMode IS "end" OR NOT thisTag.hasEndTag>
<cfparam name="ATTRIBUTES.filterUrl" type="string" default=""/>
<cfparam name="ATTRIBUTES.filter" type="struct" default=#structNew()#/>
<cfparam name="ATTRIBUTES.fwx" type="string" default=""/>
<cfset qString="#ATTRIBUTES.fwx#"/>
<!---Чтобы передавать параметры в URL (и не пользоваться сессией), надо правильно форматировать параметры всех типов--->
<!--- <cfloop collection=#ATTRIBUTES.filter# item="item">
<cftry>
<cfset fltr=structFind(ATTRIBUTES.filter,item)/>
<cfset qString=listAppend(qString, "#item#=#fltr.val#", "&")/>
<cfcatch type="ANY"></cfcatch>
</cftry>
</cfloop>--->
<cfset filterOn=request.filterOn(ATTRIBUTES.filter)/>
<!--- actually, any non-empty string can be assigned to reset_filter --->
<cfoutput><a href="#ATTRIBUTES.filterUrl#?#qString#"><cfif filterOn><b>#request.i18("Фильтр...","Filter")#</b><cfelse>#request.i18("Фильтр","Filter")#</cfif></b></a>
<cfif filterOn><a href="#request.thisPage#?reset_filter=yes">(#request.i18("снять","reset")#)</a></cfif></cfoutput>
</cfif>
+18
View File
@@ -0,0 +1,18 @@
<cfsilent>
<cfparam name="ATTRIBUTES.titleMap" default=#structNew()#/>
<cfparam name="ATTRIBUTES.sortArray" default=#arrayNew(1)#/>
<cfset attributeList="titleMap,sortArray"/>
<cfset extraAttributes=structNew()/>
<cfloop collection=#ATTRIBUTES# item="attr">
<cfif NOT listFindNoCase(attributeList, attr)>
<cfset val="#structFind(ATTRIBUTES, attr)#"/>
<cfif IsSimpleValue(val)>
<cfset structInsert(extraAttributes, attr, val)/>
</cfif>
</cfif>
</cfloop>
</cfsilent><!---
---><cfif thisTag.executionMode is "start"><tr><cfelseif thisTag.executionMode is "end"></tr></cfif>
+82
View File
@@ -0,0 +1,82 @@
<cfsilent>
<cfimport prefix="m" taglib="../lib"/>
<cfimport prefix="c" taglib="../lib/controls"/>
<cfparam name="ATTRIBUTES.useSummary" default="yes"/>
<cfparam name="ATTRIBUTES.addtionalUrlParams" type="string" default=""/>
<cfparam name="ATTRIBUTES.self" default=""/>
<cfparam name="ATTRIBUTES.recordCount" default="0"/>
<cfparam name="ATTRIBUTES.totalCount" default="0"/>
<cfparam name="ATTRIBUTES.recordsPerPage" default="500"/>
<cfparam name="ATTRIBUTES.footerOut" default=""/>
<cfparam name="ATTRIBUTES.excelLink" default="No"/>
<cfparam name="ATTRIBUTES.jsonLink" default="No"/>
<cfparam name="ATTRIBUTES.buttonNew" default="No"/>
<cfparam name="ATTRIBUTES.buttonNewTitle" default="Создать"/>
<cfparam name="ATTRIBUTES.urlNew" default=""/>
<cfset UrlSuffix=""/>
<cfif len(ATTRIBUTES.addtionalUrlParams) GT 0>
<cfset UrlSuffix="&#ATTRIBUTES.addtionalUrlParams#"/>
</cfif>
<cfif len(ATTRIBUTES.self) GT 0>
<cfset UrlSuffix="&track=#ATTRIBUTES.self#"/>
</cfif>
<c:paginator
thisPage=#request.thisPage#
recordCount=#ATTRIBUTES.recordCount#
recordsPerPage=#ATTRIBUTES.recordsPerPage#
self=#ATTRIBUTES.self#
addtionalUrlParams=#ATTRIBUTES.addtionalUrlParams#
output="paginator"/>
</cfsilent>
<cfoutput>
<cfif ATTRIBUTES.useSummary>
<div class="table wide" style="margin:3px 0;">
<div class="td" style="height:2em; line-height:2em; padding-left:0; vertical-align:middle;">
<cfif ATTRIBUTES.buttonNew>
<button type="button" class="maincontrol" onclick="document.location.href='#ATTRIBUTES.urlNew#'" style="margin:.0 1.5em 0 0;">
<a href="#ATTRIBUTES.urlNew#">#ATTRIBUTES.buttonNewTitle#</a>
</button>
<cfelse>
<div style="display:inline-block; width:1em;"/>&nbsp;</div>
</cfif>
<cfif (ATTRIBUTES.recordCount GE 0)>
Выбрано <b>#ATTRIBUTES.recordCount#</b>
<cfif (ATTRIBUTES.totalCount GE 0)>
из <b>#ATTRIBUTES.totalCount#</b>
</cfif>
</cfif>
<cfif ATTRIBUTES.excelLink>
<a href="#request.thisPage#?output_xls#UrlSuffix#" title="экспорт в Excel" style="margin-left:.5em; height:100%;" target="_blank"><img src="img/xls.gif" style="vertical-align:text-bottom;"/></a>
</cfif>
<cfif ATTRIBUTES.jsonLink>
<a href="#request.thisPage#?output_json#UrlSuffix#" title="экспорт в json" style="margin-left:.5em; height:100%;" target="_blank"><img src="img/json.svg" style="vertical-align:text-bottom;" width="13" height="13"/></a>
</cfif>
</div>
<div class="td r">
#paginator.links#
</div>
</div>
</cfif>
</cfoutput>
<cfif len(ATTRIBUTES.footerOut)>
<cfsavecontent variable="CALLER.#ATTRIBUTES.footerOut#">
<cfoutput>
<div class="wide r" style="margin:0.3em">
#paginator.links#
</div>
</cfoutput>
</cfsavecontent>
</cfif>
<cfexit method="exittag"/>
+99
View File
@@ -0,0 +1,99 @@
<cfsilent>
<cfparam name="ATTRIBUTES.qRead" type="query"/>
<cfparam name="ATTRIBUTES.convertSnakeToCamel" type="boolean" default=true/>
<!---<cfdump var=#qRead#/>
<cfdump var=#ATTRIBUTES.titleMap#/>
<cfabort/>--->
<cffunction name="snake2camel"
returntype="string"
output="false"
hint="convert snake style name to camel style name">
<cfargument name="snake" type="string" required="true" />
<cfreturn #reReplace(ARGUMENTS.snake,"_([a-z])","\u\1","ALL")#/>
</cffunction>
<cffunction name="camel2snake"
returntype="string"
output="false"
hint="convert camel style name to snake style name">
<cfargument name="camel" type="string" required="true" />
<cfreturn #reReplace(ARGUMENTS.camel,"([A-Z])","_\l\1","ALL")#/>
</cffunction>
<!--- <cffunction name="escape4json"
returntype="string"
output="false"
hint="escape string for json format">
<cfargument name="s" type="string" required="true" />
<cfreturn #reReplace(ARGUMENTS.camel,"([A-Z])","_\l\1","ALL")#/>
</cffunction> --->
<!--- <cffunction name="query2array">
<cfargument name="qry" type="query" required="true"/><!--- column names should not contain commas --->
<cfargument name="convertSnakeToCamel" type="boolean" default=true/><cfsilent>
</cffunction> --->
<!--- <cffunction name="query2json"
output="true"
hint="print query in json format as array of structures">
<cfargument name="qry" type="query" required="true"/><!--- column names should not contain commas --->
<cfargument name="convertSnakeToCamel" type="boolean" default=true/><cfsilent>
<cfset var columnsIn=#qry.columnList()#/>
<cfset var columnsOut=""/>
<cfif arguments.convertSnakeToCamel>
<cfloop list=#columnsIn# item="col">
<cfset columnsOut=listAppend(columnsOut,snake2camel(col))/>
</cfloop>
<cfelse>
<cfset columnsOut=#columnsIn#/>
</cfif>
</cfsilent>[<cfoutput query=#qry#>{<cfloop index="i" from="1" to=#listLen(columnsOut)#>"#listGetAt(#columnsOut#,i)#":"#qry[listGetAt(#columnsIn#,i)]#"<cfif #i# LT #listLen(columnsOut)#>,</cfif></cfloop>}<cfif #qry.currentRow()# LT #qry.recordCount()#>,</cfif></cfoutput>]
</cffunction> --->
<cffunction name="query2json"
output="false"
hint="print query in json format as array of structures">
<cfargument name="qry" type="query" required="true"/><!--- column names should not contain commas --->
<cfargument name="convertSnakeToCamel" type="boolean" default=true/>
<cfset var columnsIn=#arguments.qry.columnList()#/>
<cfset var columnsOut=""/>
<cfif arguments.convertSnakeToCamel>
<cfloop list=#columnsIn# item="col">
<cfset columnsOut=listAppend(columnsOut,snake2camel(col))/>
</cfloop>
<cfset var outArray=arrayNew(1)/>
//copy fields to structure, renaming fields, this preserves data type
<cfloop query=#arguments.qry#>
<cfset var structRow=structNew()/>
<cfloop index="i" from="1" to=#listLen(columnsOut)#>
<cfset structInsert(structRow,"#listGetAt(#columnsOut#,i)#",arguments.qry["#listGetAt(#columnsIn#,i)#"])/>
</cfloop>
<cfset arrayAppend(outArray,structRow)/>
</cfloop>
<cfreturn serializeJSON(outArray)/>
<cfelse>
<cfreturn serializeJSON(arguments.qry,"struct")/>
</cfif>
</cffunction>
<!--- <cfset request.camel2snake = camel2snake/> --->
<!---<cfsavecontent variable="strXmlData">--->
<!--- <cfif ATTRIBUTES.snake2camel>
<cfloop collection=#ATTRIBUTES.qRead.columnList# item="col">
<cfset queryRenameColumn(ATTRIBUTES.qRead,col,snake2camel(col))/>
<cfset ATTRIBUTES.qREAD.
</cfloop>
</cfif> --->
<cfset msStartAt=getTickCount()/>
</cfsilent><cfcontent
type="application/json"
/><cfoutput>#query2json(ATTRIBUTES.qRead,ATTRIBUTES.convertSnakeToCamel)#</cfoutput><!---
,<cfoutput>"duration":"#(getTickCount()- msStartAt)#"</cfoutput>} --->
<cfexit method="exittag"/>
+9
View File
@@ -0,0 +1,9 @@
<cfif thisTag.executionMode IS "end" OR NOT thisTag.hasEndTag>
<cfoutput>
&nbsp;
&nbsp;
&nbsp;
<a href="?language=ru"<cfif request.language EQ 'ru'> style="font-weight:bold;"</cfif>>Ru</a>
<a href="?language=en"<cfif request.language EQ 'en'> style="font-weight:bold;"</cfif>>En</a>
</cfoutput>
</cfif>
+240
View File
@@ -0,0 +1,240 @@
<cfsilent><!--- *** http://www.bennadel.com/blog/457-a-case-against-coldfusion-custom-tag-page-wrappers.htm--->
<cfimport prefix="layout" taglib="../layout"/>
<cfimport prefix="c" taglib="../lib/controls"/>
<cfparam name="ATTRIBUTES.section" type="string"/>
<cfparam name="ATTRIBUTES.closeForm" type="boolean" default="No"/>
<cfparam name="title" default=""/><!---заголовок страницы, отображаемый в теле например, <h1>--->
<cfparam name="pageTitle" default="PAYG"/><!---заголовок окна браузера, в теге <title>--->
<cfparam name="controls" default=""/>
</cfsilent><cfsilent>
<!---Тег layout:page проглатывает собственный контент, и вместо него после закрытия выводит разметку на основании атрибутов (при открытии тега он формирует переменные - фрагменты разметки - по шаблону) и вложенных тегов layout:attribute (которые по закрытии тега на самом деле перезаписывают переменные в layout:page).
Вложенные теги удобны, чтобы передавать читабельную разметку, а не строку в кавычках.--->
<cfif thisTag.executionMode IS "start">
<!--- Формируется значение переменной controls--->
<!--- Но оно может быть переопределено вызовом layout:attribute в теле тега <layout:page>--->
<cfif #ATTRIBUTES.section# EQ "header">
<cfparam name="ATTRIBUTES.pageInfo" type="struct"/><!--- инициализируется вызывающей страницей --->
<cfsavecontent variable="controls">
<cfoutput>
<cfswitch expression=#ATTRIBUTES.pageInfo.getType()#>
<cfcase value="ls">
<layout:filter_link filterUrl="#ATTRIBUTES.pageInfo.entity#_filter.cfm" filter=#ATTRIBUTES.pageInfo.settings.filter# fwx="#ATTRIBUTES.pageInfo.track.fwx#" />
</cfcase>
<cfcase value="detail">
<layout:detail_buttons backUrl="#ATTRIBUTES.pageInfo.track.backUrl#" enable="#ATTRIBUTES.pageInfo.writePermitted()#"/>
<!---<cfset ATTRIBUTES.form="1"/>--->
</cfcase>
<cfcase value="filter">
<layout:filter_buttons backUrl="#ATTRIBUTES.pageInfo.track.backUrl#"/>
<!---<cfset ATTRIBUTES.form="1"/>--->
</cfcase><!--- *** not implemented
<cfcase value="del">
<layout:del_buttons backUrl="#ATTRIBUTES.pageInfo.track.backUrl#"/>
<cfset ATTRIBUTES.form="1"/>
</cfcase>--->
<cfdefaultcase>
<!---<cfthrow message="Unsupported page type" detail="Supported page types are ls, detail, filter, del"/>--->
</cfdefaultcase>
</cfswitch>
<!---<layout:language_switch/>--->
</cfoutput>
</cfsavecontent>
</cfif>
</cfif>
<!--- Переменную (фрагмент разметки) title по традиции заполняем в вызывающей странице через layout:attribute--->
</cfsilent><!---
<!---*******************************************--->
---><cfif thisTag.executionMode IS "end"><!---
---><cfsilent>
<!---никакая разметка из тела даннного тега не выводится,
вместо этого по закрытии тега им генерируется собственный контент--->
<!---внутри тега на странице определяются его параметры, некорректно названные атрибутами--->
<cfset thisTag.generatedContent=""/><!---
---></cfsilent><!---
---><cfswitch expression=#ATTRIBUTES.section#><!---
---><cfcase value="header"><cfsilent>
</cfsilent><!--- ----------------------------------------------------------------------------
---------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------
---><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="en" xml:lang="en" xmlns= "http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/><!--- this should be the first line in head --->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<script type="text/javascript">
var timerStart = Date.now();
</script>
<!---<cfquery name="qUsr" datasource="#request.DS#">
select login, firstname, middlename, lastname from worker where id='#request.usr_id#'
</cfquery>--->
<title><cfoutput>#pageTitle#</cfoutput></title>
<link rel="shortcut icon" href="img/favicon.ico"/>
<!--- <link rel="stylesheet" href="style/fontawesome-all.css"/> --->
<link rel="stylesheet" type="text/css" href="style/web.css"/>
<!--- override layout header style --->
<!--- <cfswitch expression=#request.STAND#>
<cfcase value="DEV">
<style>.title, .main-controls {background-color:#aaf}</style>
</cfcase>
<cfcase value="TEST">
<style>.title, .main-controls {background-color:#9e9}</style>
</cfcase>
<cfcase value="PROD">
<style>.title, .main-controls {background-color:#faa}</style>
</cfcase>
<cfdefaultcase>
<style>.title, .main-controls {background-color:#aaa}</style><!--- без изменений --->
</cfdefaultcase>
</cfswitch> --->
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/jquery.searchabledropdown.js"></script>
<script>
function resetListsById(id){
for (var i = 0, j = arguments.length; i < j; i++) {
try {
document.getElementById(arguments[i]).selectedIndex=-1;
} catch (e) {}
}
}
window.onload=function(){document.body.style.cursor='default';}
</script>
</head>
<body style="cursor:wait;"><a name="up"></a> <!--- <cfdump var=#ATTRIBUTES.pageInfo.writePermitted()#/> --->
<div class="page">
<div class="page-main">
<div class="menu noprint" style="margin:0; padding:0;/*border:1px solid red;*/">
<div class="fixed-menu" style="width:145px; height:100%; padding:0 0 0 0; --border:1px solid blue;" />
<a name="up"></a>
<!---<a id="lime_ref" href="http://root" style="display:inline-block; margin: 0; padding: 0 6px; height: 30px; width: 48px; margin: 5px 0 0 0;" title="Home"><img src="img/alarm-arrow-up-icon.png" style="margin: 0; padding: 0; height: 30px; margin: 5px 0 0 0;"/></a>
--->
<!--- <div style="width:20px; height:30px; margin: 5px; background: url('img/logo0.png') 0 0 no-repeat; background-size:contain; display:inline-block;"></div>--->
<div style="width:138px; height:30px; margin: 5px 0 0 5px; background: url('img/logo0.png') 0 0 no-repeat; background-size:contain; display:inline-block; -border:1px solid red;">
<p class="b r" style="color:white; margin:0 10px 10px 10px; font-size:130%;">
Спецификации
</p>
</div>
<p style="color:lightgray; margin:10px 12px; text-align:right;">
<cfoutput>v.#request.APP_VERSION#</cfoutput>
</p>
<style>
.menu-items-container::-webkit-scrollbar {width: 10px; margin:10px;}
}
.menu-items-container::-webkit-scrollbar-track {
background-color: lightgray;
}
.menu-items-container::-webkit-scrollbar-thumb {
--background-color: rgb(97,127,136);/*lightgray*/;
--border-radius: 2px;
--border: 1px solid white;
}
</style>
<div class="menu-items-container" style="width:100%; height:100%; overflow:auto; scrollbar-width:thin; --border:1px solid green;">
<cfmodule template="../inc/menu.cfm" fwx="#ATTRIBUTES.pageInfo.track.fwx#" thisUrl="#ATTRIBUTES.pageInfo.track.thisUrl#"/>
<br/>
<br/>
<br/>
</div>
</div>
</div>
<!-- content -->
<div class="content">
<cfif isInstanceOf(ATTRIBUTES.pageInfo, "form_page_info")>
<cfoutput>
<form name="#ATTRIBUTES.pageInfo.formName#" action="#ATTRIBUTES.pageInfo.formAction#" method="#ATTRIBUTES.pageInfo.formMethod#" <!---style="height:100%;"---><cfif len(ATTRIBUTES.pageInfo.formEncType)> enctype="#ATTRIBUTES.pageInfo.formEncType#"</cfif>><!--- height:100% is required to make inner elements fill the container vertically ---><!--- but if we close the form in the middle of the page, layout is broken --->
</cfoutput>
</cfif>
<div class="header">
<div class="control-bar">
<!--- <div style="display:table-cell; width:23px; background: #ccc/*rgb(117,147,156)*/; border: 1px solid #bbb;"> --->
<!--- <div style="display:table-cell; width:23px; background: #0078c9; border: 1px solid #000;"> --->
<!--- <div style="display:table-cell; width:23px; background: #07b; border: 1px solid #000;"></div> --->
<!--- <div style="display:table-cell; width:3px;"></div> --->
<div class="title">
<cfoutput>#title#</cfoutput>
</div>
<div class="main-controls">
<cfoutput>#controls#</cfoutput>
</div>
</div><!--- control-bar --->
</div>
<div class="layout_vspacer"></div>
<cfif len(ATTRIBUTES.pageInfo.status.errorState)>
<span style="color:red"><cfoutput>#ATTRIBUTES.pageInfo.status.errorMessage#</cfoutput></span>
<cfexit method="exittag"/>
</cfif>
<!-- content -->
</cfcase><cfcase value="extension"><!--- -------------------------------------------------------------------------------------------- --->
<cfif ATTRIBUTES.closeForm></form></cfif>
</cfcase><cfcase value="footer"><!--- -------------------------------------------------------------------------------------------- --->
<!--/content -->
<cfif ATTRIBUTES.closeForm></form></cfif>
</div>
<!--/content -->
</div><!--- page main --->
<div class="page-footer noprint">
<div style="display:table-cell; padding:.5em; background-color:#555;">
<cftry>
<cfset pageTimeMs=GetTickCount()-request.startTickCount/>
<cfoutput><span title="page generation time">#pageTimeMs# ms</span></cfoutput>
<cfcatch type="any">request.startTickCount undefined</cfcatch>
</cftry>
<span id="load-time" title="page loading time"></span>
<script type="text/javascript">
window.onload=function() {
document.body.style.cursor='default';
document.getElementById("load-time").innerHTML = (Date.now()-timerStart) + " ms";
};
<!---alert(document.documentMode);// IE troubles --->
</script>
</div>
<div style="display:table-cell; padding: 3px;">
<div class="footer">
<cftry>
<cflock scope="session" type="readonly" timeout="3">
<cfif len(session.authentication_source)>
<cfoutput>authentication:#session.authentication_source#</cfoutput>&nbsp;
</cfif>
</cflock><cfcatch type="ANY"></cfcatch></cftry>
<a href="#up" class="up">вверх</a>
</div>
</div>
</div>
</div><!--- page --->
<!--- fixed-menu class is defined at the bottom of page, so in case of unhandled error menu is not fixed --->
<style>
div.fixed-menu { position:fixed;}
</style>
</body>
</html><!---
---></cfcase><cfdefaultcase><cfthrow message="Unsupported 'section' attribute value" detail="Supported section values are 'header','extension','footer'"></cfdefaultcase></cfswitch><!---
---></cfif>
+55
View File
@@ -0,0 +1,55 @@
<!---https://www.bennadel.com/blog/461-creating-microsoft-excel-documents-with-coldfusion-and-xml.htm--->
<!---*** locale-specific--->
<cfparam name="ATTRIBUTES.qRead" type="query"/>
<cfparam name="ATTRIBUTES.titleMap" type="struct"/>
<cfparam name="ATTRIBUTES.sheetTitle" type="string" default="Sheet1"/>
<cfparam name="ATTRIBUTES.filename" type="string" default="export.xls"/>
<cfset fieldArray=structSort(ATTRIBUTES.titleMap, "numeric", "ASC", "ordinal")/>
<cfsavecontent variable="strXmlData">
<cfoutput>
<html xmlns:o='urn:schemas-microsoft-com:office:office' xmlns:x='urn:schemas-microsoft-com:office:excel' xmlns='http://www.w3.org/TR/REC-html40'><meta http-equiv="content-type" content="application/vnd.ms-excel; charset=UTF-8"><meta http-equiv="content-type" content="application/vnd.ms-excel; charset=UTF-8"><head><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>#ATTRIBUTES.sheetTitle#</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--></head><body><table><!---
<cfloop index="i" from="1" to=#structCount(ATTRIBUTES.titleMap)#>
<Column ss:Index="#i#"/>
</cfloop>
--->
<tr>
<cfloop from=1 to=#arrayLen(fieldArray)# index="i">
<cfset title=structFind(ATTRIBUTES.titleMap, fieldArray[i]).title/>
<th><cfif len(title)>#title#<cfelse>#fieldArray[i]#</cfif></th>
</cfloop>
</tr>
<cfloop query=#ATTRIBUTES.qRead#>
<tr>
<cfloop from=1 to=#arrayLen(fieldArray)# index="i">
<cfset data=#ATTRIBUTES.qRead[fieldArray[i]]#/>
<cftry>
<cfif isDate(data)><td>#dateFormat(data,'YYYY-MM-DD')#<cfif hour(data) GT 0 OR minute(data) EQ 0> #timeFormat(data,'HH:mm')#</cfif></td><cfelseif isNumeric(data)><td>#Replace(data, '.', ',')#</td><cfelse><td>#data#</td></cfif>
<cfcatch type="Any"><td>#data#</td></cfcatch>
</cftry>
</cfloop>
</tr>
</cfloop>
</table></body></html>
</cfoutput>
</cfsavecontent>
<cfheader
name="content-disposition"
value="attachment; filename=#ATTRIBUTES.filename#"
/>
<!---
When streaming the Excel XML data, trim the data and
replace all the inter-tag white space. No need to stream
any more content than we have to.
--->
<cfcontent
type="application/msexcel"
variable="#ToBinary( ToBase64( strXmlData.Trim().ReplaceAll( '>\s+', '>' ).ReplaceAll( '\s+<', '<' ) ) )#"
/><cfabort/>
<cfexit method="exittag"/>
+49
View File
@@ -0,0 +1,49 @@
<!---https://www.bennadel.com/blog/461-creating-microsoft-excel-documents-with-coldfusion-and-xml.htm--->
<cfparam name="ATTRIBUTES.qRead" type="query"/>
<cfparam name="ATTRIBUTES.titleMap" type="struct"/>
<cfparam name="ATTRIBUTES.sheetTitle" type="string" default="Sheet1"/>
<cfparam name="ATTRIBUTES.filename" type="string" default="export.xlsx"/>
<cfsavecontent variable="strXmlData">
<cfoutput>
<html xmlns:o='urn:schemas-microsoft-com:office:office' xmlns:x='urn:schemas-microsoft-com:office:excel' xmlns='http://www.w3.org/TR/REC-html40'>
<meta http-equiv="content-type" content="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet">
<head><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>xlsWorksheetName</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--></head>
<body>
<table>
<tr>
<cfloop struct=#ATTRIBUTES.titleMap# item="field">
<th>#structFind(ATTRIBUTES.titleMap,field).title#</th>
</cfloop>
</tr>
<cfloop query=#ATTRIBUTES.qRead#>
<tr>
<cfloop struct=#ATTRIBUTES.titleMap# item="field">
<td>
#ATTRIBUTES.qRead[field]#
</td>
</cfloop>
</tr>
</cfloop>
</table>
</body>
</html>
</cfoutput>
</cfsavecontent>
<cfheader
name="content-disposition"
value="attachment; filename=#ATTRIBUTES.filename#"
/>
<!---
When streaming the Excel XML data, trim the data and
replace all the inter-tag white space. No need to stream
any more content than we have to.
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
--->
<cfcontent
type="application/vnd.ms-excel"
variable="#ToBinary( ToBase64( strXmlData.Trim().ReplaceAll( '>\s+', '>' ).ReplaceAll( '\s+<', '<' ) ) )#"
/>
<cfexit method="exittag"/>
+239
View File
@@ -0,0 +1,239 @@
<cfsilent>
<!---https://www.bennadel.com/blog/461-creating-microsoft-excel-documents-with-coldfusion-and-xml.htm--->
<!---порядок колонок, как в селекте, не управляется никак
Для определения порядка колонок используется поле ATTRIBUTES.titleMap.ordinal, возможно, не самый надежный способ
Можно попробовать использовать порядок колонок в массиве query --->
<cfparam name="ATTRIBUTES.qRead" type="query"/>
<cfparam name="ATTRIBUTES.titleMap" type="struct"/><!---see ../lib/data/field_set.cfm--->
<cfparam name="ATTRIBUTES.sheetTitle" type="string" default="Sheet1"/>
<cfparam name="ATTRIBUTES.filename" type="string" default="export.xlsx"/>
<cfset AVG_SYMBOL_WIDTH=6.5/>
<cfset MAX_COL_LENGTH=30/>
<cfset qRead=ATTRIBUTES.qRead/>
<!---<cfdump var=#qRead#/>
<cfdump var=#ATTRIBUTES.titleMap#/>
<cfabort/>
--->
<!---<cfsavecontent variable="strXmlData">--->
</cfsilent><cfheader
name="content-disposition"
value="attachment; filename=#ATTRIBUTES.filename#"
/><cfcontent
type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
/><cfoutput><?xml version="1.0"?>
<?mso-application progid="Excel.Sheet"?>
<!---
This is the Workbook root element. This element
stores characteristics and properties of the
workbook, such as the namespaces used in
SpreadsheetML.
--->
<Workbook
xmlns="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:html="http://www.w3.org/TR/REC-html40">
<!---
The first child element of the WorkBook element
is DocumentProperties. Office documents store
metadata related to the document&#8212;for example,
the author name, company, creation date, and
more in the DocumentProperties element.
--->
<DocumentProperties
xmlns="urn:schemas-microsoft-com:office:office">
<Author>xls-generator</Author>
<Company></Company>
</DocumentProperties>
<!---
The Styles node represents information related
to individual styles that can be used to format
components of the workbook.
--->
<Styles>
<!--- Basic format used by all cells. --->
<Style ss:ID="Default" ss:Name="Normal">
<Alignment ss:Vertical="Top"/>
<Borders/>
<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="11"/>
<Interior/>
<NumberFormat/>
<Protection/>
</Style>
<Style ss:ID="Th">
<Alignment ss:Horizontal="Center" ss:Vertical="Top"/>
<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="11" ss:Bold="1"/>
</Style>
<Style ss:ID="Int">
<NumberFormat ss:Format="0" />
</Style>
<Style ss:ID="DateTime">
<NumberFormat ss:Format="dd/mm/yyyy\ hh:mm;@"/>
</Style>
<!---
<Style ss:ID="ShortDate">
<NumberFormat ss:Format="[ENG][$-409]d\-mmm\-yyyy;@" />
</Style>
<Style ss:ID="YesNo">
<NumberFormat ss:Format="Yes/No" />
</Style>
--->
</Styles>
<!---
This defines the first worksheeet and it's name.
We are only using one worksheet in this example,
but you could add more Worksheet nodes after
this one for multiple tabs. The "Name" attribute
here is the name that shows up in the tab.
--->
<Worksheet ss:Name="#ATTRIBUTES.sheetTitle#">
<Table
<!---
We need a column for each column of the
query. This attribute is required to be
correct. If the value here does NOT
match the data in Excel file, the
document will not render properly.
--->
ss:ExpandedColumnCount="#ListLen(qRead.ColumnList)#"
<!---
We need a row for every query record
plus one for the header row. Again, if
this value does not match what is in the
document, the excel file will not
render properly.
--->
ss:ExpandedRowCount="#(qRead.RecordCount + 1)#"
x:FullColumns="1"
x:FullRows="1">
<!---
Here, we can define general properties
regarding each column in the data output.
<Column ss:Index="1" ss:Width="30" />
<Column ss:Index="2" ss:Width="100" />
<Column ss:Index="3" ss:Width="42" />
<Column ss:Index="4" ss:Width="84" />
<Column ss:Index="5" ss:Width="66" />
<Column ss:Index="6" ss:Width="70" />--->
<cfsilent>
<cfset columns=arrayNew(1)/>
<cfset i=1/>
<cfloop struct=#ATTRIBUTES.titleMap# item="field">
<cfset col=structNew()/>
<cfset fieldSpec=structFind(ATTRIBUTES.titleMap, field)/>
<cfset col.name=field/>
<cfset col.title=fieldSpec.title/>
<cfif len(col.title) EQ 0>
<cfset col.title=col.name/>
</cfif>
<cfset col.titleLength=len(col.title)/>
<cfquery name="qLen" dbtype="query">
select coalesce(max(length(#field#)),0) as maxlen from qRead
</cfquery>
<cfset col.length=max(col.titleLength, qLen.maxLen)/>
<cfset col.cfSqlType="CF_SQL_VARCHAR"/>
<cfif structKeyExists(fieldSpec,"cfSqlType")>
<cfset col.cfSqlType=#fieldSpec.cfSqlType#/>
</cfif>
<cfswitch expression=#col.cfSqlType#><!---should use ## around variable name--->
<cfcase value="CF_SQL_BIGINT,CF_SQL_INTEGER,CF_SQL_SMALLINT,CF_SQL_TINYINT,CF_SQL_BIT,CF_SQL_NUMERIC,CF_SQL_DECIMAL,CF_SQL_REAL,CF_SQL_FLOAT,CF_SQL_DOUBLE">
<cfset col.ssType="Number"/>
</cfcase>
<cfcase value="CF_SQL_TIMESTAMP,CF_SQL_DATE,CF_SQL_TIME,CF_SQL_DATETIME">
<cfset col.ssType="DateTime"/>
</cfcase>
<cfdefaultcase>
<cfset col.ssType="String"/>
</cfdefaultcase>
</cfswitch>
<cfset columns[fieldSpec.ordinal]=col/><!---new col created at each iteration, so we have valid references--->
<cfset i=i+1/>
</cfloop>
</cfsilent>
<cfloop from=1 to=#arrayLen(columns)# index="i">
<cfif columns[i].ssType EQ "DateTime"><!--- timestamp string representation is too long, --->
<Column ss:Index="#i#" ss:Width="#round(min(columns[i].titleLength, MAX_COL_LENGTH)*AVG_SYMBOL_WIDTH)#" ss:AutoFitWidth="1"/>
<cfelse>
<Column ss:Index="#i#" ss:Width="#round(min(columns[i].length, MAX_COL_LENGTH)*AVG_SYMBOL_WIDTH)#" ss:AutoFitWidth="1"/>
</cfif>
</cfloop>
<!---
This is our header row. All cells in the
header row will be of type string.
--->
<Row>
<cfloop from=1 to=#arrayLen(columns)# index="i">
<Cell ss:StyleID="Th">
<Data ss:Type="String">#columns[i].title#</Data>
</Cell>
</cfloop>
</Row>
<cfflush/>
<cfloop query=#qRead#><!---
---><Row><!---
---><cfloop from=1 to=#ArrayLen(columns)# index="i"><!---
---><cfset field=columns[i].name/><!---
---><Cell<cfif columns[i].ssType EQ "DateTime"> ss:StyleID="DateTime"</cfif>><!---
---><cfif len(qRead[field])><Data ss:Type="#columns[i].ssType#"><!---no extra whitespace allowed here---><!---
---><cfswitch expression=#columns[i].ssType#><!---
---><cfcase value="DateTime"><!---
--->#dateFormat(qRead[field],"YYYY-MM-DD")#T#timeFormat(qRead[field],"HH:mm:ss.l")#<!---
---></cfcase><!---
---><cfcase value="Number"><!---
--->#qRead[field]#<!---
---></cfcase><!---
---><cfdefaultcase><!---
---><![CDATA[#request.clean4CDATA(qRead[field])#]]><!---
---></cfdefaultcase><!---
---></cfswitch><!---
---></Data></cfif><!---
---></Cell><!---
---></cfloop><!---
---></Row><!---
---></cfloop><!---
---></Table>
</Worksheet>
</Workbook>
</cfoutput>
<!---</cfsavecontent>--->
<!---
Define the way in which the browser should interpret
the content that we are about to stream.
--->
<!---<cfheader
name="content-disposition"
value="attachment; filename=#ATTRIBUTES.filename#"
/>--->
<!---
When streaming the Excel XML data, trim the data and
replace all the inter-tag white space. No need to stream
any more content than we have to..ReplaceAll( '>\s+', '>' ).ReplaceAll( '\s+<', '<' )
--->
<!---<cfcontent
type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
variable="#ToBinary( ToBase64( strXmlData.Trim()))#"
/>---><!---<cfabort/>--->
<cfexit method="exittag"/>
+593
View File
@@ -0,0 +1,593 @@
<cfsilent>
<cfimport prefix="m" taglib="lib"/>
<cfimport prefix="c" taglib="lib/controls"/>
<cfimport prefix="d" taglib="lib/data"/>
<cfimport prefix="layout" taglib="layout"/>
</cfsilent>
<m:prepare_ls entity="payg" accessObject="" pageInfoOut="pageInfo" trackOut="tr"/>
<cfparam name="dt_finish" type="date" default=#createDateTime(year(Now()),month(Now()),1,0,0,0)#/>
<cfparam name="dt_start" type="date" default=#dateAdd('m',-1,dt_finish)#/>
<cfset hours=dateDiff('h',dt_start,dt_finish)/>
<!--- Нужно еще применить политики бесплатного минимума --->
<cfquery name="qCode" datasource="dwh">
select distinct p.code
from elma.deals d
join elma.deals_services siv on (d.__id=ANY(siv.deal))
join elma.service_parametrs p on (p.__id = ANY(siv.params))
join elma.companies k on (d._companies=k.__id)
join elma.additional_agreements aa on (aa.__id = ANY(siv.additional_agreement))
join elma.aggrements a on (aa.contract_uid = a.__id)
where p.type=3 AND aa.is_actual
order by p.code
</cfquery>
<!--- <cfdump var=#qCode#/> --->
<cfquery name="qSpec" datasource="dwh">
select k.id_klienta as wz, k.__id::text as contragent_uid, p.code, p.price, p.discount, k.__name as contragent, a.__name as contract, a.__id::text as contract_uid, d.__name as deal, d.__id::text as deal_uid, siv.abstractive_service as abstract_service, siv.modifier, siv.user_description, siv.hash as line_key
,siv.date_nop as dt_from, siv.date_end as dt_to
/*,p.__name as line_key*/, p.ed_izm, aa.__name as additional_agreement, aa.__id::text as additional_agreement_uid
--, aa.is_actual
from elma.deals d
join elma.deals_services siv on (d.__id=ANY(siv.deal))
join elma.service_parametrs p on (p.__id = ANY(siv.params))
join elma.companies k on (d._companies=k.__id)
join elma.additional_agreements aa on (aa.__id = ANY(siv.additional_agreement))
join elma.aggrements a on (aa.contract_uid = a.__id)
where p.type=3 AND aa.is_actual
order by k.id_klienta, p.code
</cfquery>
<cfquery name="qSivAge" datasource="dwh">
select max(dt_load) as dt_load from elma.deals_services
</cfquery>
<!--- здесь имеем список кодов с ценами и WZ. Каждому коду можно поставить в соответствие запрос, который даст по нему выборку. Изредка один запрос может вывести 2 кода, но разбить на 2 запроса легко. Кроме того, запросы можно объединить через union в один - может быть, так будет лучше читаться (быстрее выполняться не будет) --->
<cfif isDefined("DEBUG")>
<cfdump var=#qSpec#/>
<cfflush/>
</cfif>
<cfquery name="qComputing" datasource="billing-vc">
select 'WZ'||to_char(tenant.wzcode,'FM00000') as wz, vdc.name as vdc_name,
case
when vdc.name like '%-v1cl1%' then 'iaas.ngc.i29'
when vdc.name like '%-v1cl2%' then 'iaas.ngc.i31'
when vdc.name like '%-v1cl4%' then 'iaas.ngc.a28'
when vdc.name like '%-v1cl6%' then 'iaas.ngc.i28'
else '['||vdc.name||']' end as code,
sum(cpu_used/cpu_speed)/4. as core_h,
sum(mem_used)/1024/4. as gb_h
from ngcloud_ru.capacity_resource
join ngcloud_ru.vdc on capacity_resource.vdc_id=vdc.id
join ngcloud_ru.tenant on tenant.id=vdc.tenant_id
where tenant.wzcode > 0
AND capacity_resource.timestamp >= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_start#/>
AND capacity_resource.timestamp < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_finish#/>
group by tenant.wzcode, vdc.name
order by tenant.wzcode, vdc.name;
</cfquery>
<!--- <cfdump var=#qComputing#/> --->
<cfquery name="qComputingAge" datasource="billing-vc">
select max(capacity_resource.timestamp) as dt_load from ngcloud_ru.capacity_resource
</cfquery>
<!--- переделать storage_profile_types с расшифровкой ssd, sata, можно прямо до каталожного кода --->
<cfquery name="qStorage" datasource="billing-vc">
select 'WZ'||to_char(tenant.wzcode,'FM00000') as wz, vdc.name as vdc_name,
case
WHEN vdc.name LIKE '%-v1cl1%' THEN 'iaas.ngc.i29'
WHEN vdc.name LIKE '%-v1cl2%' THEN 'iaas.ngc.i31'
WHEN vdc.name LIKE '%-v1cl4%' THEN 'iaas.ngc.a28'
WHEN vdc.name LIKE '%-v1cl6%' THEN 'iaas.ngc.i28'
ELSE '['||vdc.name||']' END
|| CASE
WHEN storage_profile_types.name ILIKE '%-SSD%' THEN '.ssd-m'
WHEN storage_profile_types.name ILIKE '%-SAS' THEN '.sas-m'
WHEN storage_profile_types.name ILIKE '%-SATA' THEN '.sata-m'
ELSE '.['|| storage_profile_types.name ||']' END
as code,
storage_profile_types.name, -- *** это не тип, а профайл
sum("limit")/1024./4 as gb_h_limit, -- 4 потому, что сбор раз в 15 минут
sum(used)/1024./4 as gb_h_used
from ngcloud_ru.capacity_storage
join ngcloud_ru.vdc on capacity_storage.vdc_id=vdc.id
join ngcloud_ru.tenant on tenant.id=vdc.tenant_id
join ngcloud_ru.storage_profile_types on capacity_storage.storage_profile_types_id=storage_profile_types.id
where tenant.wzcode > 0
AND capacity_storage.timestamp >= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_start#/>
AND capacity_storage.timestamp < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_finish#/>
group by tenant.wzcode, vdc.name, storage_profile_types.name
order by tenant.wzcode, vdc.name, storage_profile_types.name;
</cfquery>
<cfquery name="qStorageAge" datasource="billing-vc">
select max(capacity_storage.timestamp) as dt_load from ngcloud_ru.capacity_storage
</cfquery>
<!--- <cfdump var=#qStorage#/> --->
<!---
"placement" "size_gb" "get_10k" "put_10k" "bytes_sent_gb"
HOT_FREE_LIMIT 1 10 1 100
--->
<!--- надо дисконтировать не ГБ-часы а ГБ-месяцы --->
<cfquery name="qS3Vol" datasource="billing-s3">
select /* *** ниже дублирование кода агрегации - round ceil etc, обратить внимание при правке */
(sum(bucket_stat.usage_rgw_main_size_actual)/<cfqueryparam cfsqltype="cf_sql_integer" value=#hours#/>) as vol_B
,round(sum(bucket_stat.usage_rgw_main_size_actual)/<cfqueryparam cfsqltype="cf_sql_integer" value=#hours#/>/1024/1024/1024) as vol_GB
,greatest(round(sum(bucket_stat.usage_rgw_main_size_actual)/<cfqueryparam cfsqltype="cf_sql_integer" value=#hours#/>
/1024/1024/1024)-
case when bucket_stat.placement_id = 1 then 1 else 0 end, 0) as vol_GB_free_tier_subtracted /*считается не в точности так, как в функции*/
,case
when bucket_stat.placement_id = 1 then 'paas.s3.ceph'
when bucket_stat.placement_id = 2 then 'paas.s3.cphc'
else '['|| TO_CHAR(bucket_stat.placement_id,'FM9') ||']' end as code
--,bucket_stat.placement_id
,'WZ'||lpad(bucket_stat.owner, 5, '0') as wz -- *** здесь не число, а строка, поэтому другая формула обратной сборки WZ
from s3billing.bucket_stat
join s3billing.placement ON s3billing.placement.id=bucket_stat.placement_id
join s3billing.bucket_info ON bucket_info.id=bucket_stat.bucket_id
where bucket_stat.placement_id in (1,2)
AND bucket_stat.timestamp_addition >= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_start#/>
AND bucket_stat.timestamp_addition < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_finish#/>
group by bucket_stat.owner, bucket_stat.placement_id
order by bucket_stat.owner, bucket_stat.placement_id;
</cfquery>
<!--- <cfdump var=#qS3Vol#/> --->
<cfquery name="qS3VolAge" datasource="billing-s3">
select max(timestamp_addition) as dt_load from s3billing.bucket_stat
</cfquery>
<cfquery name="qS3OpsTrf" datasource="billing-s3">
select
sum(
CASE WHEN
(category.name LIKE 'get%'
OR category.name LIKE 'head%'
OR category.name LIKE 'options%'
) THEN ops ELSE 0 END
) as get
,ceil(sum(
CASE WHEN
(category.name LIKE 'get%'
OR category.name LIKE 'head%'
OR category.name LIKE 'options%'
) THEN ops ELSE 0 END
)/10000) as get_10k
,greatest(ceil(sum(
CASE WHEN
(category.name LIKE 'get%'
OR category.name LIKE 'head%'
OR category.name LIKE 'options%'
) THEN ops ELSE 0 END
)/10000) - CASE WHEN bucket_info.placement_id = 1 THEN 10 ELSE 0 END, 0
) as get_10k_free_tier_subtracted
,sum(
CASE WHEN
(category.name LIKE 'put%'
OR category.name LIKE 'post%'
OR category.name LIKE 'patch%'
OR category.name LIKE 'list%'
) THEN ops ELSE 0 END
) as put
,ceil(sum(
CASE WHEN
(category.name LIKE 'put%'
OR category.name LIKE 'post%'
OR category.name LIKE 'patch%'
OR category.name LIKE 'list%'
) THEN ops ELSE 0 END
)/10000) as put_10k
,greatest(ceil(sum(
CASE WHEN
(category.name LIKE 'put%'
OR category.name LIKE 'post%'
OR category.name LIKE 'patch%'
OR category.name LIKE 'list%'
) THEN ops ELSE 0 END
)/10000) - CASE WHEN bucket_info.placement_id = 1 THEN 1 ELSE 0 END, 0
) as put_10k_free_tier_subtracted
,(sum(bytes_sent)) as bytes_sent
,ceil(sum(bytes_sent)/1024/1024/1024) as bytes_sent_GB
,greatest(ceil(sum(bytes_sent)/1024/1024/1024) - CASE WHEN bucket_info.placement_id = 1 THEN 100 ELSE 0 END, 0
) as bytes_sent_GB_free_tier_subtracted
,case
when bucket_info.placement_id = 1 then 'paas.s3.ceph'
when bucket_info.placement_id = 2 then 'paas.s3.cphc'
else '['|| TO_CHAR(bucket_info.placement_id,'FM9') ||']' end as code --*** зачем делать там ключ bigint
,bucket_info.placement_id
--category.name, bucket_info.name
,'WZ'||lpad(user_info.name, 5, '0') as wz
from s3billing.usage_bucket_by_user
join s3billing.user_info on usage_bucket_by_user.user_id=user_info.id
join s3billing.category on usage_bucket_by_user.category_id=category.id
join s3billing.bucket_info on usage_bucket_by_user.bucketid=bucket_info.id
join s3billing.placement on bucket_info.placement_id=placement.id
where 1=1
AND usage_bucket_by_user.time >= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_start#/>
AND usage_bucket_by_user.time < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#dt_finish#/>
group by user_info.name, bucket_info.placement_id
order by user_info.name, bucket_info.placement_id;
</cfquery>
<cfquery name="qS3OpsTrfAge" datasource="billing-s3">
select max(time) as dt_load from s3billing.usage_bucket_by_user
</cfquery>
<!--- <cfdump var=#qS3OpsTrf#/> --->
<cfquery name="qUnifiedMetric" dbType="query">
select wz, code || '.cpu-m' as code, core_h as raw_metric, core_h as metric, core_h as chargeable_metric from qComputing
union all
select wz, code || '.ram-m' as code, gb_h as raw_metric, gb_h as metric, gb_h as chargeable_metric from qComputing
union all
select wz, code, gb_h_used as raw_metric, gb_h_used as metric, gb_h_used as chargeable_metric from qStorage
union all
select wz, code || '.vol-m', vol_b as raw_metric, vol_gb as metric, vol_GB_free_tier_subtracted as chargeable_metric from qS3Vol
union all
select wz, code || '.get-m', get as raw_metric, get_10k as metric, get_10k_free_tier_subtracted as chargeable_metric from qS3OpsTrf
union all
select wz, code || '.put-m', put as raw_metric, put_10k as metric, put_10k_free_tier_subtracted as chargeable_metric from qS3OpsTrf
union all
select wz, code || '.trf-m', bytes_sent as raw_metric, bytes_sent_gb as metric, bytes_sent_gb_free_tier_subtracted as chargeable_metric from qS3OpsTrf
</cfquery>
<cfif isDefined("DEBUG")>
<cfdump var=#qUnifiedMetric#/>
<cfflush/>
</cfif>
<cfquery name="qCharge" dbType="query">
SELECT
s.wz
,s.code
,s.price
,s.discount
,s.contragent, s.contragent_uid
,s.contract,s.contract_uid
,s.deal, s.deal_uid
,s.additional_agreement, s.additional_agreement_uid
,s.abstract_service
,s.modifier
,user_description
,s.ed_izm
,s.line_key, s.dt_from, s.dt_to
,s.deal,s.abstract_service,s.modifier,s.user_description
,m.raw_metric
,m.metric
,m.chargeable_metric
,s.price*(100-s.discount)/100 as discounted_price
,s.price*(100-s.discount)/100*m.chargeable_metric as charge
FROM qSpec as s, qUnifiedMetric as m WHERE s.wz=m.wz AND s.code=m.code
order by s.wz, s.code
</cfquery>
<!--- looks like QoQ does not support join syntax, at least of Lucee 5.4--->
<layout:page section="header" pageInfo=#pageInfo#>
<layout:attribute name="title">
<cfoutput><b>Отчет по PAYG</b></cfoutput>
</layout:attribute>
<layout:attribute name="controls">
<!---skip filter link, filter is not implemented--->
<!---<layout:language_switch/>--->
</layout:attribute>
</layout:page>
Внимание! округление вверх при расчете метрик get, put S3. Расчетные суммы могут содержать погрешности округления, поэтому окончательный расчет стоимости (количество * цену) должен выполняться в бухгалтерской программе.
<b>Если у клиента больше 1 действующего допника с услугами PAYG, то данные в отчете могут быть замножены, в этом случае считать вручную</b>
<br/>
Даты актуальности пока проверять вручную
<cfoutput>
<form method="post" action="">
Период с <input type="text" name="dt_start" value="#dateFormat(dt_start,'YYYY-MM-DD')#"/>
по <input type="text" name="dt_finish" value="#dateFormat(dt_finish,'YYYY-MM-DD')#"/>
<input type="submit" style="cursor:pointer;"/>
<input type="submit" name="DEBUG" value="DEBUG" style="cursor:pointer;"/>
</form>
Часов в периоде: <b>#hours#</b> Строк в отчете: <b>#qCharge.recordCount#</b><br/>
Актуальность данных:
VCD Computing: <b>#dateFormat(qComputingAge.dt_load,'YYYY-MM-DD')# #timeFormat(qComputingAge.dt_load,'HH:MM:SS')#</b>
VCD Storage: <b>#dateFormat(qStorageAge.dt_load,'YYYY-MM-DD')# #timeFormat(qStorageAge.dt_load,'HH:MM:SS')#</b>
S3 хранение: <b>#dateFormat(qS3VolAge.dt_load,'YYYY-MM-DD')# #timeFormat(qS3VolAge.dt_load,'HH:MM:SS')#</b>
S3 операции и трафик: <b>#dateFormat(qS3OpsTrfAge.dt_load,'YYYY-MM-DD')# #timeFormat(qS3OpsTrfAge.dt_load,'HH:MM:SS')#</b>
</cfoutput>
<!--- <cfdump var=#dt_start#/>
<cfdump var=#dt_finish#/>
<cfdump var=#hours#/> --->
<table class="worktable">
<thead>
<td width="1%"></td>
<td width="3%">WZ</td>
<td width="5%">Артикул</td>
<td width="3%">Цена без НДС проверить</td>
<td width="3%">Кол-во (метрика)</td>
<td width="3%">Ед.изм.</td>
<td width="3%">Ст-ть</td>
<td width="3%">&nbsp;&nbsp;&nbsp;</td>
<td width="6%">Дата НОУ</td>
<td width="6%">Дата оконч.</td>
<td width="3%">Ключ строки</td>
<td width="3%">GPL без НДС проверить</td>
<td width="3%">Скидка%</td>
<td width="3%">Сырая метрика</td>
<td width="3%">Приведен&shy;ная метрика</td>
<td width="7%">Контрагент</td>
<td width="3%">Договор</td>
<td width="3%">Допник</td>
<td width="3%">Сделка</td>
<td width="10%">Услуга</td>
<td width="8%">Клиентс. назв.</td>
</thead>
<cfoutput query="qCharge" group="wz">
<cfset var acc=0/>
<cfoutput>
<cfset acc=acc+charge/>
<tr>
<td>#currentRow#</a></td>
<td><a href="contragent.cfm?__id=#contragent_uid#&#tr.fwx#">#wz#</a></td>
<td>#code#</td>
<td class="r">#discounted_price#</td>
<td class="r">#chargeable_metric#</td>
<td>#ed_izm#</td>
<td class="r">#charge#</td>
<td></td>
<td class="r">#dateFormat(dt_from,'YYYY-MM-DD')#</td>
<td class="r">#dateFormat(dt_to,'YYYY-MM-DD')#</td>
<td class="r">#line_key#</td>
<td class="r">#price#</td>
<td class="r">#discount#</td>
<td class="r" style="color:lightgray">#raw_metric#</td>
<td class="r">#metric#</td>
<td><a href="contragent.cfm?__id=#contragent_uid#&#tr.fwx#">#contragent#</a></td>
<td><a href="contract.cfm?__id=#contract_uid#&#tr.fwx#">#contract#</a></td>
<td><a href="additional_agreement.cfm?__id=#additional_agreement_uid#&#tr.fwx#">#additional_agreement#</a></td>
<td><a href="deal.cfm?__id=#deal_uid#&#tr.fwx#">#deal#</a></td>
<td>#abstract_service# #modifier#</td>
<td>#user_description#</td>
</tr>
</cfoutput>
<tr>
<td></td>
<td colspan="5" class="b"><a href="contragent.cfm?__id=#contragent_uid#&#tr.fwx#">#wz#</a> #contragent#</td>
<td colspan="1" class="r b">#NumFmt(acc,2)#</td>
<td colspan="14"></td>
</tr>
</cfoutput>
</table>
<!--- <cfdump var=#qCharge#/> --->
<layout:page section="footer"/>
<!---
--->
<!--- --,m.*
--,s.price*(100-s.discount)/100 as discounted_price
-- --->
<!--- В одном месте user_id int в другом owner varchar --->
<!---
задача (вызванная сыростью базы биллинга)
смапить код параметра с VDC (1:n)
iaas.ngc.i31.ram-m
iaas.ngc.a28.ram-m
cl01:
7 хостов Lenovo ThinkSystem SR650 -[7X06CTO1WW]-
2 процессора Xeon(R) Gold 6226R 16 ядер 32 потока каждый 2.9 ГГц
1.25тб озу в каждом.
В 4 из 7 есть по 4 GPU NVIDIA A16 16GB в каждом.
cl01-vsan:
16 хостов Lenovo ThinkSystem SR650 -[7X06CTO1WW]-
2 процессора Xeon(R) Gold 6226R 16 ядер 32 потока каждый 2.9 ГГц
1.25тб озу в каждом.
В 9 из 16 есть по 4 GPU NVIDIA A16 16GB в каждом.
cl02:
10 Huawei 2488H V5
4 процессора Xeon(R) Gold 6254 18 ядер 36 потоков каждый. 3.1 ГГц
2тб озу в каждом.
5 Huawei Atlas 800 (Model 3010)
2 процессора Xeon(R) Gold 6254 18 ядер 36 потоков каждый. 3.1 ГГц
1.5тб озу в каждом.
cl04-vsan:
10 Apex AR320-12
2 процессора AMD EPYC 7543 32 ядра 64 потока каждый. 2.8 ГГц
2тб озу в каждом.
18 Apex AR320-12-E7543
2 процессора AMD EPYC 7543 32 ядра 64 потока каждый. 2.8 ГГц
2тб озу в каждом.
cl05-1c:
1 Asus RS720A-E12-RS24U
2 процессора AMD EPYC 9274F 24 ядра 48 потоков каждый. 4.05 ГГц
1тб озу.
7 ручная сборка
MB Asus ProArt B650-Creator
Процессор AMD Ryzen 9 7950X 16 ядер 32 потока каждый. 4.5 ГГц
192гб озу каждый.
1 ручная сборка
процессор AMD Ryzen Threadripper PRO 5995WX 64 ядра 128 потоков каждый. 2.7 ГГц
512гб озу.
cl06-vsan:
15 R320
2 процессора Xeon(R) Gold 6342 24 ядра 48 потоков каждый. 2.8 ГГц
1тб озу каждый.
Xeon(R) Gold 6226R 2.9 ГГц
Xeon(R) Gold 6254 3.1 ГГц
AMD EPYC 7543 2.8 ГГц
AMD EPYC 9274F 4.05 ГГц
AMD Ryzen 9 7950X 4.5 ГГц
AMD Ryzen Threadripper PRO 5995WX 2.7 ГГц
Xeon(R) Gold 6342 2.8 ГГц --->
<!--- 2025-08-15 20:47:44 *** Операции S3 считаются не так, как написано в тарифе. Например, считается list. В тарифе вообще не описан минимальный лимит --->
<!--- BEGIN
RETURN QUERY
(
select
billing_per_user_fix_pl.placement as placement,
(CASE
WHEN ( billing_per_user_fix_pl.placement = 'HOT'
) THEN greatest(ceil(sum(size)/1024/1024/1024)-1,0)
WHEN ( not billing_per_user_fix_pl.placement = 'HOT'
) THEN ceil(sum(size)/1024/1024/1024)
END) AS size_GB,
(CASE
WHEN ( billing_per_user_fix_pl.placement = 'HOT'
) THEN greatest(ceil(sum(get)/10000)-10,0)
WHEN ( not billing_per_user_fix_pl.placement = 'HOT'
) THEN ceil(sum(get)/10000)
END) AS get_10k,
(CASE
WHEN ( billing_per_user_fix_pl.placement = 'HOT'
) THEN greatest(ceil(sum(put)/10000)-1,0)
WHEN ( not billing_per_user_fix_pl.placement = 'HOT'
) THEN ceil(sum(put)/10000)
END) AS put_10k,
(CASE
WHEN ( billing_per_user_fix_pl.placement = 'HOT'
) then greatest(ceil(sum(bytes_sent)/1024/1024/1024)-100,0)
WHEN ( not billing_per_user_fix_pl.placement = 'HOT'
) THEN ceil(sum(bytes_sent)/1024/1024/1024)
END) AS bytes_sent_GB
from s3billing.billing_per_user_fix_pl(_ds,_df,_user)
group by billing_per_user_fix_pl.placement
UNION all
select
'HOT_FREE_LIMIT' as placement,
'1' AS size_GB,
'10' AS get_10k,
'1' AS put_10k,
'100' AS bytes_sent_GB
);
END; --->
<!---
BEGIN
RETURN QUERY
SELECT
s3billing.bucket_info.name AS bucket_name,
(case
when ( s3billing.placement.name = 'default-placement') then 'HOT'
WHEN ( not s3billing.placement.name = 'default-placement' ) THEN s3billing.placement.name
end
) as placement,
coalesce(round(sum(usage_rgw_main_size_actual)/
(SELECT (DATE_PART('day',
((TO_TIMESTAMP(_df, 'YYYY-MM-DD HH24:MI:SS'))
-TO_TIMESTAMP(_ds, 'YYYY-MM-DD HH24:MI:SS'))
)*24+
DATE_PART('hour',
((TO_TIMESTAMP(_df, 'YYYY-MM-DD HH24:MI:SS'))
-TO_TIMESTAMP(_ds, 'YYYY-MM-DD HH24:MI:SS'))
)))
)::numeric,0) AS size
,coalesce(s2.get, 0) AS get
,coalesce(s2.put, 0) AS put
,coalesce(s2.bytes_sent, 0) as bytes_sent
FROM s3billing.bucket_stat
INNER JOIN s3billing.placement ON s3billing.bucket_stat.placement_id=s3billing.placement.id
INNER JOIN s3billing.bucket_info ON s3billing.bucket_stat.bucket_id=s3billing.bucket_info.id
LEFT JOIN (
SELECT
s1.bucket_id AS bucket_id
,s1.bucket_name AS bucket_name,
(case
when ( s1.placement = 'default-placement') then 'HOT'
WHEN ( not s1.placement = 'default-placement' ) THEN s1.placement
end
) as placement
,coalesce(sum(s1.get) ,0) AS get
,coalesce(sum(s1.put) ,0) AS put
,coalesce(sum(s1.bytes_sent), 0) AS bytes_sent
FROM (
SELECT
s3billing.bucket_info.id AS bucket_id
,s3billing.bucket_info.name AS bucket_name
,(case
when ( s3billing.placement.name = 'default-placement') then 'HOT'
WHEN ( not s3billing.placement.name = 'default-placement' ) THEN s3billing.placement.name
end
) as placement
,(CASE
WHEN ( s3billing.category.name LIKE 'get%'
OR s3billing.category.name LIKE 'head%'
OR s3billing.category.name LIKE 'options%'
) THEN coalesce(sum(ops), 0)
END) AS get
,(CASE
WHEN ( s3billing.category.name LIKE 'put%'
OR s3billing.category.name LIKE 'post%'
OR s3billing.category.name LIKE 'patch%'
OR s3billing.category.name LIKE 'list%'
) THEN coalesce(sum(ops), 0)
END) AS put
,coalesce(sum(usage_bucket_by_user.bytes_sent), 0) AS bytes_sent
FROM
s3billing.usage_bucket_by_user
INNER JOIN s3billing.bucket_info ON s3billing.usage_bucket_by_user.bucketid = s3billing.bucket_info.id
INNER JOIN s3billing.placement ON s3billing.bucket_info.placement_id = s3billing.placement.id
INNER JOIN s3billing.user_info ON s3billing.usage_bucket_by_user.user_id = s3billing.user_info.id
INNER JOIN s3billing.category ON s3billing.usage_bucket_by_user.category_id = s3billing.category.id
WHERE
s3billing.user_info.name=_user
AND s3billing.usage_bucket_by_user.time >=TO_TIMESTAMP(_ds, 'YYYY-MM-DD HH24:MI:SS')
AND s3billing.usage_bucket_by_user.time < TO_TIMESTAMP(_df, 'YYYY-MM-DD HH24:MI:SS')
GROUP BY
s3billing.bucket_info.name
,s3billing.placement.name
,s3billing.category.name
,s3billing.bucket_info.id
) AS s1
GROUP BY
s1.bucket_name
,s1.bucket_id
,s1.placement
ORDER BY
s1.placement
,s1.bucket_name
) AS s2 ON s2.bucket_id = s3billing.bucket_stat.bucket_id
WHERE owner=_user
AND timestamp_addition >= TO_TIMESTAMP(_ds, 'YYYY-MM-DD HH24:MI:SS')
AND timestamp_addition < TO_TIMESTAMP(_df, 'YYYY-MM-DD HH24:MI:SS')
GROUP BY
s3billing.bucket_info.name
,s3billing.placement.name
,s3billing.bucket_stat.bucket_id
,s2.get
,s2.put
,s2.bytes_sent
ORDER BY
s3billing.placement.name
,s3billing.bucket_info.name
;
END; --->
<!--- select * from s3billing.billing_per_user_fix_pl('2025-05-01 00:00:00','2025-06-01 00:00:00','1395'); --->
+321
View File
@@ -0,0 +1,321 @@
/*common elements*/
html, body {
margin: 0;
padding: 0;
border: none;
height: 100%;
}
body, table, tr, td, th, input, select, textarea, button, form, ul, li, p {
font-size: 11px;
font-family: Tahoma, Verdana, Arial, Helvetica, sans-serif;
color:black;
}
form {margin: 0;padding:0;}
p {margin: 0.5em;}
table {border-collapse: collapse;}
img {border: none; margin: 0; vertical-align: middle;}
a, a:link, a:visited {color: #111111; text-decoration: underline;}
a:hover {color: #ff7600; text-decoration: underline;}
/* form elements */
input {color: black; padding: 0 0.3em; }
input:read-only {color:#555; background-color:#f0f0f0;}
input:disabled {color:#555; background-color:#f0f0f0;}
select:disabled {color:#555;}
select option[disabled] { color:#ddd;}
.detail .td input[type="text"]:disabled {border:1px solid #aaa; color:#555;}
.textbox-disabled {display:inline-block; border: 1px solid #aaa; color:#555; background-color:#f0f0f0; padding:.1em;}
/*layout*/
div.vspacer {height:5px;}
ul#mainmenu {
list-style-type:none;
padding:0;
margin:0;
display:block;
width:100%;
}
ul#mainmenu li {
text-align:right;
vertical-align:baseline;
padding:.2em 15px .2em 0 ;
margin:.3em 0;
background: url('../img/sarrow.gif') center right no-repeat;
font-size:120%;
font-weight:normal;
font-family: Verdana, Tahoma, Arial, Helvetica, sans-serif;
line-height: 1.1em;
}
ul#mainmenu li a{/*display:block;*/color:#cde;text-decoration:none;}
ul#mainmenu li a:hover{text-decoration:underline;}
ul#mainmenu li.selected {color: /*#4682b4;*/ #fa6 /*#00f*/;}
ul#mainmenu li.menu-item-ext {background: url('../img/external.gif') center right no-repeat;}
ul#mainmenu li.menu-item-noaction {background: none; color: #777;}
ul#mainmenu li.menu-title {
color: #111;
background:none white;
margin:.5em 0 0 0;
/*font-weight: bold;*/
/*border:1px solid #ccc;*/
}
.page {display:table; table-layout: fixed; width:100%; height:100%;}
.page-main {display:table-row; height:100%;}
.page-footer {display:table-row; height:1px;}
.menu {display:table-cell; width:150px; padding:0 0 0 .5em; background-color: #012; -border:1px solid red;}
.content {display:table-cell; height:100%; vertical-align:top; padding: 3px;}
.header {display:block; /*background:url('../img/portlet_dot.gif') center left no-repeat; padding-left:33px;*/ line-height: 21px; font-family: Verdana, Tahoma, sans-serif;}
.control-bar {display:table; width:100%; color:/*#559*/white; /*border:1px solid #ccc;*/ height:19px; }
.header .control-bar a:link, .header .control-bar a:visited {color:white; padding: .2em .5em;}
.header .control-bar a:hover {background:white;color:#f90; padding: .2em .5em;}
.title {display:table-cell; padding:1px 12px; vertical-align:middle; font-size:110%; background-color:#aaa/*#ccc*//*rgb(117,147,156)*/; /*color:#fa6;*/ border: 1px solid #bbb; border-right:none;}
.title b {color:#026;}
.main-controls {display:table-cell; padding:0 7px; text-align:right; vertical-align: middle; background-color:#aaa/*rgb(117,147,156)*/; border: 1px solid #bbb; border-left:none;}
.footer {height:21px; line-height: 21px; background-color:#e0e0e0; border:1px solid #bbb; text-align: right; vertical-align: middle; padding:0 3px;}
.table {display:table;}
.tr {display:table-row;}
.td, .th {display:table-cell; padding: 0 0.5em; vertical-align:top;}
.detail {
display:table;
width:100%;
margin: 3px 0;
border:1px solid #ddd;
border-collapse: collapse;
}
.detail .tr{
line-height: 1.5em;
}
.detail .th {
display:table-cell;
text-align:right;
background-color:#e0e0e0;
padding:0.35em 0.5em;
border:none;
/*color: #5f5f5f;*/
font-weight:normal;
vertical-align:top;
/*border:1px solid red;*/
}
.detail .td {
display:table-cell;
background-color:#e7e7e7;
padding:0.2em 0.5em;
border:1px solid #ddd;
vertical-align:baseline;
}
.detail .td input, .detail .td select, .detail .td img, .detail .td button, .detail .td div, .detail .td span {
vertical-align: baseline;
margin: 0 0.3em;
}
.detail .td label {
vertical-align: baseline;
margin: 0 0.3em 0 0;
line-height:normal;
}
.detail .td input[type="checkbox"] {
vertical-align: top; margin: 0 0 0 0.3em;
}
/*.detail .td input[type="text"] {
width: 97%;
}*/
.detail .td textarea {
color: black;
width: 97%;
margin-left: 0.2em;
padding: 0.2em 0.5em;
}
/***hack*/
.detail .td a img {vertical-align:text-bottom;}
.filter {background-color: #f7f7f7;}
.disabled, tr.disabled td, tr.disabled th {color: #888;}
.plate {background-color:#f0f0f0; padding:.1em; border:1px solid #ddd;}
button, .button, .content a.button:link {
background: #fafafa;
-background: -webkit-linear-gradient(top, #fafafa 0%, #f4f4f4 40%,#e5e5e5 100%);
background:-webkit-linear-gradient(top, #dde 0%, #cde 40%,#bcd 100%);
border: 1px solid #aad;
padding: 1px 10px;
color: #black;
border-radius: 3px;
box-shadow: 0 1px 1px #ddd;
}
button:disabled, .button:disabled, .maincontrol:disabled {
background: #fafafa;
background: -webkit-linear-gradient(top, #fafafa 0%,#f4f4f4 40%,#e5e5e5 100%);
border-color: #aaa;
color: #999;
box-shadow: none;
}
button:not(:disabled):hover,
.button:not(:disabled):hover,
.maincontrol:not(:disabled):hover
{
background: #fefefe;
background: -webkit-linear-gradient(top, #fefefe 0%,#f8f8f8 40%,#e9e9e9 100%);
box-shadow: 0 1px 3px rgba(7, 7, 7, 0.35);
border: 1px solid #aaa;
color: #ff7600;
}
button:not(:disabled):active, .button:not(:disabled):active {
background: #f4f4f4;
background: -webkit-linear-gradient(top, #f4f4f4 0%,#efefef 40%,#dcdcdc 100%);
box-shadow: inset 0 1px 3px rgba(7, 7, 7, 0.35);
}
button.maincontrol {
/*background-color:#c3c82f;
background:-webkit-linear-gradient(top, #cd6 0%, #cd6 40%,#bc5 100%);*/
-background-color:#6fa0f0;
background-color:#6fa0f0;
background:-webkit-linear-gradient(top, #dde 0%, #cde 40%,#bcd 100%);
color: black;
}
button.maincontrol:hover {
}
/*не совсем аккуратно, при нажатии выглядит чуть иначе, чем кнопка*/
.content button a, .content button a:link, .content button a:visited {color: #790; text-decoration:none; cursor:default;}
.content button:hover a, .content button:active {color: #ff7600; text-decoration:none; cursor:default;}
.content button.maincontrol a, .content button.maincontrol a:link,.content button.maincontrol a:visited {color: black;}
.content button.maincontrol:hover a, .content button.maincontrol:active a {color: #ff7600;}
.submitnew {
background-image:url('../img/new.gif');
width:13px; height:13px; border:none; padding:0; color:transparent; cursor:pointer;
}
.submitsave {
background-image:url('../img/save.gif');
width:14px; height:14px; border:none; padding:0; color:transparent; cursor:pointer;
}
.submitdel {
background-image:url('../img/del.gif');
width:13px; height:13px; border:none; padding:0; color:transparent; cursor:pointer;
}
.submitminus {
background-image:url('../img/minus.gif');
width:13px; height:13px; border:none; padding:0; color:transparent; cursor:pointer;
}
.content a, .content a:link, .content a:visited {color: #1111ee; text-decoration: none;}
.content a:hover {color: #ff7600; text-decoration: underline;}
.content h4 {margin-block-end: .5em;}
.content i {color:#555;}
.cell {border: 1px solid #ddd; width:100%; padding: 0.2em;}
.l, td.l, th.l{text-align: left;}
.r, td.r, th.r{text-align: right;}
.c, td.c, th.c{text-align: center;}
.nw {white-space: nowrap;}
.b {font-weight:bold;}
.i {font-style:italic;}
.wide {min-width:100%}
.wh100 {width:100%; height:100%;}
.table {display:table}
.tcell {display:table-cell}
.mid {vertical-align:middle} /*используется для заполнения ячейки таблицы якорем a href*/
.err {color: red;}
.warn {color: #f80;}
a.up {background: url('../img/up.gif') center right no-repeat; padding-right: 7px;}
a.add {background: url('../img/add.gif') center right no-repeat; width:13px; height:13px; display:inline-block;}
a.edit {background: url('../img/edit.gif') center right no-repeat; width:13px; height:13px; display:inline-block;}
a.view {background: url('../img/view.gif') center right no-repeat; width:13px; height:13px; display:inline-block;}
a.del {background: url('../img/del.gif') center right no-repeat; width:13px; height:13px; display:inline-block;}
/* worktable classes */
table.worktable {border-collapse:separate; border-spacing:0; border-left:1px solid #ddd;}
table.worktable th,
table.worktable td {
border-bottom: thin solid #ddd;
border-right: thin solid #ddd;
}
table.worktable thead th,
table.worktable thead td {
box-shadow: 0 -1px 0 0 #ddd;
}
table.worktable thead {
top: 0;
left: 0;
position: sticky;
z-index: 1;
}
table.worktable td p {margin:0;}
table.worktable thead tr td, table.worktable tr th{padding: 3px; background-color: #999;}
table.worktable tr {height: 1.7em; background-color: white;}
table.worktable tr td {padding:0.1em 0.3em; height:2em;}
table.worktable tr:hover, table.worktable tr td:hover {background-color:#e5e5e5;}
table.worktable th {font-weight:500; color:white;}
/*double borders - not tested with border-collapse:separate*/
table.worktable tbody tr td.lbd,
table.worktable thead tr td.lbd
{border-left: double #ccc;}
table.worktable tbody tr td.rbd,
table.worktable thead tr td.rbd
{border-right: double #ccc;}
table.worktable tbody tr td.tbd,
table.worktable thead tr td.tbd,
table.worktable tbody tr.tbd td,
table.worktable thead tr.tbd td
{border-top: double #ccc;}
table.worktable tbody tr td.bbd,
table.worktable thead tr td.bbd,
table.worktable tbody tr.bbd td,
table.worktable thead tr.bbd td
{border-bottom: double #ccc;}
table.worktable tr.hist {background-color: #f6f6f6;}
table.worktable tr.hist:hover, table.worktable tr.hist:hover td, table.worktable tr.comment:hover{background-color:#efefef;}
table.worktable tr.hist td.marked {background: #ddf5c0;}
table.worktable tr.hist:hover td.marked{background-color:#d0f0b9;}
@media print {
#mainmenu, .menu, .page-footer, .control-bar, .noprint {display:none;}
}