v0.5.13: gitignore разработческих файлов (DevOps-чистота)
@@ -12,12 +12,27 @@ token*.*
|
||||
# Внутренняя аналитика — не для публичного доступа
|
||||
PROJECT-AUDIT.md
|
||||
AGENT-DIAGNOSIS.md
|
||||
AGENT.md
|
||||
CONTEXT.md
|
||||
prompt-opus-*.md
|
||||
docs/questions-devops.md
|
||||
docs/PLAN-*.md
|
||||
docs/STATE-*.md
|
||||
docs/cluster-cleanup-*.md
|
||||
docs/tests-*.md
|
||||
docs/test-api.sh
|
||||
docs/nubes-design-system.md
|
||||
docs/deploy-vm.md
|
||||
|
||||
# Результаты код-ревью агентов
|
||||
research/opus-review-*.md
|
||||
research/
|
||||
|
||||
# Тестовые данные (токены, HAR, etc)
|
||||
Files/
|
||||
token*.*
|
||||
|
||||
# Логи тестов
|
||||
test-results/
|
||||
research/opus-full-review-*.md
|
||||
research/REVIEW-SUMMARY.md
|
||||
docs/STATE-old.md
|
||||
|
||||
@@ -1,473 +0,0 @@
|
||||
# AGENT.md — Полное руководство по проекту IPWhiteList
|
||||
|
||||
> Этот файл предназначен для AI-агентов и разработчиков без контекста.
|
||||
> Читай этот файл **первым** перед любой задачей.
|
||||
> Обновляй после значимых изменений.
|
||||
|
||||
---
|
||||
|
||||
## 1. Суть проекта
|
||||
|
||||
**IP WhiteList** — веб-приложение для управления белыми IP-списками (CIDR) по компаниям.
|
||||
|
||||
- Каждая компания имеет свой список IPv4/CIDR записей.
|
||||
- Есть лимит записей на компанию (по умолчанию 15, admin может менять).
|
||||
- Есть одна роль admin (задаётся через env) и обычные пользователи.
|
||||
- Аутентификация через JWT (RS256): в проде — внешний OIDC (Keycloak/Nubes auth-api), в dev — mock.
|
||||
- Весь UI — server-side rendered (EJS). API — REST JSON.
|
||||
|
||||
---
|
||||
|
||||
## 2. Репозиторий и деплой
|
||||
|
||||
| Параметр | Значение |
|
||||
|---|---|
|
||||
| Репо (рабочий) | `https://gitea.services.ngcloud.ru/Nail/ipwhitelist-app.git` ветка `master` |
|
||||
| Локальный путь | `/home/naeel/ipwhitelist-app` |
|
||||
| Деплой URL | `https://white.nodejsk8s.dev.nubes.ru` |
|
||||
| Платформа | Nubes k8s — редеплой через Nubes UI из Gitea после `git push` |
|
||||
| Версия | `package.json` → поле `version` (сейчас `0.5.0`) |
|
||||
|
||||
**Правило версий:** bump `version` в `package.json` при каждом значимом изменении.
|
||||
|
||||
---
|
||||
|
||||
## 3. Стек
|
||||
|
||||
```
|
||||
Node.js 18+ + Express 4
|
||||
EJS (server-side rendering)
|
||||
PostgreSQL 17 (pg pool, SSL require)
|
||||
jsonwebtoken RS256
|
||||
express-session + connect-pg-simple
|
||||
helmet (CSP)
|
||||
express-rate-limit
|
||||
supertest (тесты)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Переменные окружения
|
||||
|
||||
```env
|
||||
NODE_ENV=development # production → отключает DEV_MODE, требует SESSION_SECRET
|
||||
PORT=3000
|
||||
|
||||
# Auth
|
||||
DEV_MODE=true # true → mock JWT, ЗАПРЕЩЕНО в production
|
||||
DEV_SECRET= # опционально: пароль для /dev-login на staging
|
||||
ADMIN_CLIENT_ID=WZ01112 # clientId пользователя с правами admin
|
||||
JWT_ISSUER=mock-auth-api # issuer в JWT
|
||||
|
||||
# OIDC (если DEV_MODE=false)
|
||||
KC_BASE_URL=https://keycloak.nubes.ru/realms/cloud
|
||||
KC_CLIENT_ID= # пусто = mock mode
|
||||
KC_CLIENT_SECRET=
|
||||
APP_URL=http://localhost:3000
|
||||
|
||||
# База данных
|
||||
DB_HOST=write.bde8229b-1381-4330-b24b-727ad73fcb44.dev.nubes.ru
|
||||
DB_PORT=5432
|
||||
DB_NAME=ipwhitelist
|
||||
DB_USER=super
|
||||
DB_PASS=<secret>
|
||||
DB_SSLMODE=require
|
||||
|
||||
# Сессия
|
||||
SESSION_SECRET=<secret> # обязателен в production (fail-fast при запуске)
|
||||
|
||||
# Прочее
|
||||
DEFAULT_LIMIT=15 # лимит записей по умолчанию (если нет custom_limit)
|
||||
API_BASE=http://localhost:3000 # UI-слой → куда идти за /api/v1/*
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Структура файлов — карта ответственности
|
||||
|
||||
```
|
||||
server.js ← точка входа: helmet, session, монтирование роутеров
|
||||
src/
|
||||
config.js ← MOCK_USERS, APP_VERSION, backUrl()
|
||||
db.js ← pg Pool, checkConnection()
|
||||
auth.js ← initAuth() → { middleware, issueMockToken, ... }
|
||||
queries.js ← ВСЕ SQL-запросы — единственное место работы с БД
|
||||
validators.js ← validate(cidr), overlaps(), aggregateCIDRs(), BLOCKED_RANGES
|
||||
api/
|
||||
index.js ← createApiRouter({auth, q}) — монтируется на /api/v1
|
||||
middleware/
|
||||
bearerAuth.js ← requireBearer: нет заголовка → 401 JSON
|
||||
routes/
|
||||
entries.js ← GET/POST/PATCH/DELETE /api/v1/entries + GET /api/v1/entries/export
|
||||
admin.js ← GET /api/v1/companies, PATCH limit, GET /api/v1/audit
|
||||
middleware/
|
||||
rateLimit.js ← mutationLimiter, exportLimiter, authLimiter
|
||||
session.js ← createSessionMiddleware(pool)
|
||||
csrf.js ← initCsrf() — НЕ используется в новом UI
|
||||
csp.js ← CSP_DIRECTIVES для helmet
|
||||
routes/
|
||||
export.js ← GET /export — требует авторизации (Bearer)
|
||||
exp.js ← ⚠️ ВРЕМЕННЫЙ GET /exp — без авторизации (удалить после prod)
|
||||
ui/
|
||||
index.js ← createUiRouter({auth, MOCK_USERS, authLimiter})
|
||||
api-client.js ← HTTP-клиент к /api/v1/* (берёт Bearer из session.token)
|
||||
routes/
|
||||
auth.js ← GET/POST /login, /login-token, /logout
|
||||
entries.js ← /, /add, /edit/:id, /delete/:id
|
||||
admin.js ← /admin, /admin/limit/:id, /audit
|
||||
export.js ← /export (UI-обёртка, проксирует к /api/v1/entries/export)
|
||||
views/
|
||||
index.ejs ← главная: таблица записей + форма добавления
|
||||
admin.ejs ← список компаний с лимитами (admin only)
|
||||
audit.ejs ← журнал аудита (admin only)
|
||||
ui-login.ejs ← страница входа (mock-пресеты + вставить Bearer вручную)
|
||||
error.ejs ← 403/404/500
|
||||
sql/
|
||||
schema.sql ← DDL: CREATE TABLE IF NOT EXISTS (идемпотентно)
|
||||
tests/
|
||||
integration.js ← интеграционные тесты (supertest + реальный PG)
|
||||
run-tests.js ← runner
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Поток запроса — HTTP → БД
|
||||
|
||||
### 6.1 REST API запрос
|
||||
|
||||
```
|
||||
HTTP Request
|
||||
→ server.js: helmet, session, cookieParser
|
||||
→ GET /exp → src/routes/exp.js (без auth, временный) ← ТОЛЬКО ЭТО без auth
|
||||
→ /api/v1/* → src/api/index.js
|
||||
→ requireBearer : нет заголовка Authorization: Bearer → 401 JSON
|
||||
→ auth.middleware : валидация JWT → req.user = { clientId, isAdmin, email, ... }
|
||||
→ /entries/* → src/api/routes/entries.js
|
||||
→ resolveCompany() : admin+?company=id → getCompanyById() | иначе getOrCreateCompany()
|
||||
→ q.*() : SQL через pg pool
|
||||
→ JSON response
|
||||
→ /companies, /audit → src/api/routes/admin.js
|
||||
→ apiRequireAdmin() : !isAdmin → 403 JSON
|
||||
→ q.*()
|
||||
```
|
||||
|
||||
### 6.2 UI запрос (SSR)
|
||||
|
||||
```
|
||||
HTTP Request
|
||||
→ server.js → ui/index.js (createUiRouter)
|
||||
→ createAuthRouter : /login, /login-token, /logout — публичные
|
||||
→ requireToken : нет session.token → redirect /login
|
||||
→ resolveUser : jwt.decode(token) → req.user (без верификации подписи)
|
||||
→ createEntriesRouter, createAdminRouter, createExportRouter
|
||||
→ ui/api-client.js : HTTP запрос к /api/v1/* с Bearer из session.token
|
||||
→ разбирает JSON ответ
|
||||
→ res.render('view.ejs', data)
|
||||
→ Если API вернул 401 → destroy session → redirect /login
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. req.user — структура
|
||||
|
||||
После прохождения `auth.middleware` (API) или `resolveUser` (UI):
|
||||
|
||||
```js
|
||||
req.user = {
|
||||
clientId: 'WZ01112', // из JWT claim ClientID (заглавная!)
|
||||
companyId: 'uuid-...', // из JWT claim company_id
|
||||
companyName: 'Nubes Admin', // из JWT claim company_name
|
||||
email: 'admin@nubes.ru', // из JWT claim email
|
||||
isAdmin: true, // clientId === ADMIN_CLIENT_ID
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. База данных — схема
|
||||
|
||||
```sql
|
||||
-- Компании (1 строка на WZ-номер, создаётся при первом входе)
|
||||
companies (
|
||||
id SERIAL PRIMARY KEY,
|
||||
client_id VARCHAR(64) UNIQUE NOT NULL, -- WZ01112, WZ01325 и т.д.
|
||||
name VARCHAR(255),
|
||||
custom_limit INTEGER DEFAULT NULL, -- NULL = использует DEFAULT_LIMIT
|
||||
created_at TIMESTAMPTZ,
|
||||
updated_at TIMESTAMPTZ
|
||||
)
|
||||
|
||||
-- Записи белого списка (soft delete через deleted_at)
|
||||
whitelist_entries (
|
||||
id SERIAL PRIMARY KEY,
|
||||
company_id INTEGER REFERENCES companies(id),
|
||||
value_cidr VARCHAR(18), -- '192.168.1.0/24'
|
||||
comment VARCHAR(255),
|
||||
created_by VARCHAR(255), -- email
|
||||
created_at TIMESTAMPTZ,
|
||||
updated_by VARCHAR(255),
|
||||
updated_at TIMESTAMPTZ,
|
||||
deleted_by VARCHAR(255),
|
||||
deleted_at TIMESTAMPTZ -- NULL = активная запись
|
||||
)
|
||||
-- INDEX: uq_entries_active_cidr(company_id, value_cidr) WHERE deleted_at IS NULL
|
||||
|
||||
-- Аудит
|
||||
audit_log (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_email VARCHAR(255),
|
||||
company_id INTEGER,
|
||||
action VARCHAR(32), -- 'CREATE' | 'UPDATE' | 'DELETE'
|
||||
old_value TEXT,
|
||||
new_value TEXT,
|
||||
entry_id INTEGER,
|
||||
created_at TIMESTAMPTZ
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. src/queries.js — все функции
|
||||
|
||||
| Функция | Сигнатура | Описание |
|
||||
|---|---|---|
|
||||
| `getOrCreateCompany` | `(clientId, companyName) → company` | UPSERT компании по clientId |
|
||||
| `getCompanyById` | `(id) → company\|null` | по числовому PK |
|
||||
| `getLimit` | `(company) → number` | custom_limit ?? DEFAULT_LIMIT |
|
||||
| `listEntries` | `(companyId, includeDeleted=false) → []` | список записей |
|
||||
| `createEntry` | `(companyId, rawCidr, comment, email) → {entry, wasNormalized}` | INSERT + audit (транзакция) |
|
||||
| `updateEntry` | `(entryId, companyId, rawCidr, comment, email) → {entry, wasNormalized}` | UPDATE + audit (транзакция) |
|
||||
| `deleteEntry` | `(entryId, companyId, email) → void` | soft delete + audit (транзакция) |
|
||||
| `getAllCompanies` | `() → []` | все компании + active_count |
|
||||
| `setLimit` | `(companyId, newLimit) → void` | custom_limit = newLimit |
|
||||
| `getExportCIDRs` | `(companyId=null) → string[]` | CIDR строки; null = все компании |
|
||||
| `logAudit` | `(email, companyId, action, old, new, entryId, db?) → void` | внутренняя, вызывается из транзакций |
|
||||
| `getAudit` | `(companyId=null) → []` | журнал с JOIN companies |
|
||||
|
||||
---
|
||||
|
||||
## 10. src/validators.js — функции
|
||||
|
||||
```js
|
||||
validate(rawValue)
|
||||
→ { cidr: '1.2.3.0/24', wasNormalized: boolean }
|
||||
→ throws Error если невалидно
|
||||
// Нормализует host bits, проверяет BLOCKED_RANGES
|
||||
|
||||
overlaps(cidr1, cidr2) → boolean
|
||||
// true если диапазоны пересекаются
|
||||
|
||||
aggregateCIDRs(cidrArray) → string[]
|
||||
// Объединяет пересекающиеся и смежные диапазоны → минимальный набор
|
||||
|
||||
BLOCKED_RANGES // приватные/зарезервированные диапазоны — запрещены для добавления
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. src/auth.js — initAuth()
|
||||
|
||||
```js
|
||||
const auth = await initAuth();
|
||||
// Возвращает:
|
||||
auth.middleware // Express middleware: валидирует Bearer JWT → req.user
|
||||
auth.issueMockToken(claims) → jwtString // только в mock-режиме, для тестов
|
||||
auth.jwksHandler // GET /.well-known/jwks.json (только mock)
|
||||
// OIDC-режим:
|
||||
auth.getAuthUrl(state, nonce) → string // redirect URL на Keycloak
|
||||
auth.exchangeCode(code) → {token, user} // обмен code → JWT
|
||||
```
|
||||
|
||||
**Логика определения режима:**
|
||||
- `KC_CLIENT_ID && KC_CLIENT_SECRET` → OIDC-режим
|
||||
- иначе → mock-режим (генерирует RSA-пару при старте)
|
||||
|
||||
---
|
||||
|
||||
## 12. ui/api-client.js — интерфейс
|
||||
|
||||
```js
|
||||
api.token(req) // → Bearer string из req.session.token
|
||||
api.get(path, token) // → { status, data }
|
||||
api.post(path, token, body) // → { status, data }
|
||||
api.patch(path, token, body) // → { status, data }
|
||||
api.delete(path, token) // → { status, data }
|
||||
// path примеры: '/api/v1/entries', '/api/v1/entries/42', '/api/v1/companies/5/limit'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 13. Все HTTP эндпоинты
|
||||
|
||||
### Публичные (без auth)
|
||||
| Метод | URL | Файл | Описание |
|
||||
|---|---|---|---|
|
||||
| GET | `/healthz` | server.js | k8s liveness probe |
|
||||
| GET | `/.well-known/jwks.json` | server.js | mock JWKS (только DEV_MODE) |
|
||||
| GET | `/login` | ui/routes/auth.js | страница входа |
|
||||
| POST | `/login` | ui/routes/auth.js | выбор mock-пользователя |
|
||||
| POST | `/login-token` | ui/routes/auth.js | вставить Bearer вручную |
|
||||
| GET | `/logout` | ui/routes/auth.js | destroy session |
|
||||
| GET | `/callback` | ui/routes/auth.js | OIDC callback |
|
||||
| GET | `/exp` | src/routes/exp.js | ⚠️ ВРЕМЕННЫЙ: экспорт без auth |
|
||||
|
||||
### UI (требуют session.token)
|
||||
| Метод | URL | Файл | Описание |
|
||||
|---|---|---|---|
|
||||
| GET | `/` | ui/routes/entries.js | главная страница |
|
||||
| POST | `/add` | ui/routes/entries.js | добавить запись |
|
||||
| POST | `/edit/:id` | ui/routes/entries.js | изменить запись |
|
||||
| POST | `/delete/:id` | ui/routes/entries.js | удалить запись |
|
||||
| GET | `/admin` | ui/routes/admin.js | список компаний (admin) |
|
||||
| POST | `/admin/limit/:id` | ui/routes/admin.js | изменить лимит (admin) |
|
||||
| GET | `/audit` | ui/routes/admin.js | журнал аудита (admin) |
|
||||
| GET | `/export` | ui/routes/export.js | скачать whitelist.txt |
|
||||
|
||||
### REST API `/api/v1` (требуют Bearer JWT)
|
||||
| Метод | URL | Файл | Кто | Описание |
|
||||
|---|---|---|---|---|
|
||||
| GET | `/api/v1/entries` | api/routes/entries.js | все | список + limit + used |
|
||||
| GET | `/api/v1/entries?company=<id>` | api/routes/entries.js | admin | записи другой компании |
|
||||
| POST | `/api/v1/entries` | api/routes/entries.js | все | создать |
|
||||
| PATCH | `/api/v1/entries/:id` | api/routes/entries.js | все | обновить |
|
||||
| DELETE | `/api/v1/entries/:id` | api/routes/entries.js | все | удалить |
|
||||
| GET | `/api/v1/entries/export` | api/routes/entries.js | все | text/plain CIDR |
|
||||
| GET | `/api/v1/companies` | api/routes/admin.js | admin | все компании |
|
||||
| PATCH | `/api/v1/companies/:id/limit` | api/routes/admin.js | admin | установить лимит |
|
||||
| GET | `/api/v1/audit` | api/routes/admin.js | admin | журнал аудита |
|
||||
|
||||
---
|
||||
|
||||
## 14. Rate limiting
|
||||
|
||||
| Лимитер | Применяется к | Лимит |
|
||||
|---|---|---|
|
||||
| `authLimiter` | POST /login, /login-token, GET /callback | 10 req / 5 мин |
|
||||
| `exportLimiter` | GET /export, GET /exp, GET /api/v1/entries/export | 20 req / мин |
|
||||
| `mutationLimiter` | POST /add, /edit/:id, /delete/:id | 30 req / мин |
|
||||
|
||||
---
|
||||
|
||||
## 15. Mock-пользователи (DEV_MODE=true)
|
||||
|
||||
| id | clientId | Роль | companyName | email |
|
||||
|---|---|---|---|---|
|
||||
| `admin` | `WZ01112` | **admin** | Nubes Admin | admin@nubes.ru |
|
||||
| `test` | `WZ01325` | user | Тест | tazet@narod.ru |
|
||||
| `client2` | `WZ02001` | user | Вторая Компания | user2@example.com |
|
||||
|
||||
Файл: `src/config.js` → `MOCK_USERS`
|
||||
|
||||
---
|
||||
|
||||
## 16. Бизнес-логика — важные правила
|
||||
|
||||
1. **Изоляция компаний**: везде `company_id` в WHERE — данные одной компании недоступны другой.
|
||||
2. **Транзакции с FOR UPDATE**: createEntry/updateEntry/deleteEntry блокируют строку компании — защита от race condition при параллельных вставках.
|
||||
3. **Soft delete**: `deleted_at IS NULL` = активная запись. Удалённые остаются в БД.
|
||||
4. **Дубли/пересечения**: при создании и обновлении проверяются через `overlaps()` против всех активных записей компании.
|
||||
5. **Лимит**: снижение лимита не удаляет записи — только блокирует создание новых.
|
||||
6. **CIDR нормализация**: `validate()` нормализует host bits (192.168.1.5/24 → 192.168.1.0/24), возвращает `wasNormalized: true`.
|
||||
7. **Агрегация при экспорте**: `aggregateCIDRs()` объединяет смежные диапазоны — минимальный набор.
|
||||
|
||||
---
|
||||
|
||||
## 17. HTTP коды ошибок API
|
||||
|
||||
| Код | Когда |
|
||||
|---|---|
|
||||
| 400 | Невалидный CIDR, некорректные параметры |
|
||||
| 401 | Нет/невалидный Bearer токен |
|
||||
| 403 | Не admin на admin-endpoint |
|
||||
| 404 | Запись/компания не найдена |
|
||||
| 409 | Дубликат CIDR, пересечение, лимит исчерпан |
|
||||
| 500 | Ошибки БД и прочие |
|
||||
|
||||
---
|
||||
|
||||
## 18. Запуск и тесты
|
||||
|
||||
```bash
|
||||
# Установка
|
||||
npm install
|
||||
|
||||
# Запуск локально (нужен .env с DEV_MODE=true + БД)
|
||||
node server.js
|
||||
|
||||
# API-тесты (104 штуки — CRUD, валидация, изоляция, admin, лимиты)
|
||||
npm test
|
||||
|
||||
# Стресс-тесты (191 штука — concurrency, races, boundary IPs, masks, auth attacks)
|
||||
npm run test:stress
|
||||
|
||||
# Старый UI-тест (неактуален, использует /dev-login + CSRF)
|
||||
npm run test:integration
|
||||
```
|
||||
|
||||
**Все тесты требуют реального PG подключения** (переменные из `.env`).
|
||||
|
||||
### Структура тестов (`tests/stress.js`):
|
||||
|
||||
| Раздел | Что проверяет |
|
||||
|---|---|
|
||||
| S1 | Concurrency: FOR UPDATE lock, 10-15 параллельных вставок |
|
||||
| S2 | Limit enforcement под нагрузкой, setLimit(0) |
|
||||
| S3 | Mixed CRUD: concurrent update+delete+create |
|
||||
| S4 | Auth attacks: fake key, none algorithm, missing claims |
|
||||
| S5 | Edge cases: emoji, null byte, null/''/undefined |
|
||||
| S6 | Validator: overlaps, 14 blocked ranges |
|
||||
| S7 | Session vs Bearer conflict (bearerMiddleware) |
|
||||
| S8 | All CIDR masks /0–/33 (34 теста) |
|
||||
| S9 | IP boundary values: 0.0.0.0 … 255.255.255.255 (32 теста) |
|
||||
| S10 | Token manipulation: expired, wrong issuer, future, no claims |
|
||||
| S11 | DB: double delete, update deleted, isolation |
|
||||
| S12 | Unicode: full-width, zero-width, RTL, NFC/NFD |
|
||||
| S13 | Admin privilege escalation |
|
||||
| S14 | Session: login→logout, cookie reuse |
|
||||
| S15 | Rate limit /exp, /login |
|
||||
| S16 | Export edge cases |
|
||||
| S17 | Massive concurrency: 50 createEntry, 30 delete, 20 getOrCreate |
|
||||
| S18 | CIDR normalization: host bits обнуление |
|
||||
| S19 | Each blocked range individually (14) |
|
||||
| S20 | Sequential CRUD patterns |
|
||||
| S21 | Admin cross-company CRUD |
|
||||
| S22 | Weird CIDR input: пробелы, табы, \n, 256, IPv6 (20) |
|
||||
|
||||
---
|
||||
|
||||
## 19. Известные проблемы (баги) — исправлены в v0.5.0
|
||||
|
||||
| Проблема | Статус |
|
||||
|---|---|
|
||||
| `auth.middleware` читал `req.session.user` перед Bearer → Bearer-only API нарушалось | ✅ Добавлен `bearerMiddleware` |
|
||||
| Mock admin `isAdmin: undefined` в сессии | ✅ `user.role === 'admin'` |
|
||||
| Сброс лимита (пустое поле → NaN → 400) | ✅ `null` при пустом поле |
|
||||
| `setLimit()` не проверял `rowCount` → 404 на неизвестную компанию | ✅ 404 с `e.status` |
|
||||
| Версия не поднималась при правках | ✅ `0.4.1` → `0.5.0` (9 бампов) |
|
||||
| CSP/ingress блокировал inline-обработчики (onclick, onchange) | ✅ Event delegation через `<script>` |
|
||||
| Admin при `/` редиректился на первую компанию, но не на свою | ✅ Авто-редирект на компанию admin по `clientId` |
|
||||
| Даты в UTC вместо МСК | ✅ `timeZone: 'Europe/Moscow'` |
|
||||
| Фильтр аудита: `onchange` ненадёжен | ✅ Кнопка «Применить» + `Number()` сравнение |
|
||||
| `/admin` → 500 из-за отсутствия `defaultLimit` в шаблоне | ✅ Передаётся в `render()` |
|
||||
|
||||
## 20. ⚠️ ВРЕМЕННЫЕ ЭЛЕМЕНТЫ — удалить перед продом
|
||||
|
||||
### GET /exp — публичный экспорт без авторизации (добавлен v0.4.9)
|
||||
|
||||
**Причина:** По ТЗ п. 4.7 `/export` должен быть публичным, но сейчас требует авторизацию. Создан временный `/exp` как workaround.
|
||||
|
||||
**Что удалить:**
|
||||
1. Файл `src/routes/exp.js` — полностью
|
||||
2. В `server.js` строку: `app.use(require('./src/routes/exp'));`
|
||||
|
||||
**Когда:** когда `/export` сделают публичным по ТЗ.
|
||||
|
||||
---
|
||||
|
||||
## 21. Расхождения с ТЗ (открытые задачи)
|
||||
|
||||
| Пункт ТЗ | Суть | Статус |
|
||||
|---|---|---|
|
||||
| 3.1 | Несколько компаний на пользователя | Не реализовано — ждём devops |
|
||||
| 4.1 | Отображение soft-deleted для admin | Не реализовано |
|
||||
| 4.7 | `/export` без авторизации | Обход: `/exp` (временный) |
|
||||
@@ -1,56 +0,0 @@
|
||||
# План доделок перед сдачей заказчику
|
||||
|
||||
> 2026-06-02
|
||||
|
||||
## 1. §4.7 — Агрегация CIDR в публичном /export
|
||||
|
||||
**Проблема:** публичный `/export` отдаёт сырой список, без агрегации.
|
||||
ТЗ: «подсети суммаризируются (агрегируются в минимальный набор CIDR)».
|
||||
|
||||
**Решение:** добавить `aggregateCIDRs()` в обработчик `server.js`.
|
||||
|
||||
**Файлы:** `server.js` — одна строка.
|
||||
|
||||
---
|
||||
|
||||
## 2. §4.1 — Фильтр «показать удалённые» для admin
|
||||
|
||||
**Проблема:** админ не может посмотреть soft-deleted записи.
|
||||
|
||||
**Решение:**
|
||||
- API: поддержать `?includeDeleted=true` в `GET /api/v1/entries`
|
||||
- UI: добавить чек-бокс «показать удалённые» на странице admin
|
||||
|
||||
**Файлы:** `src/api/routes/entries.js`, `views/index.ejs`.
|
||||
|
||||
---
|
||||
|
||||
## 3. §5 — Клиентская JS-валидация
|
||||
|
||||
**Проблема:** только HTML5 `pattern`, нет проверки приватных диапазонов и нормализации на клиенте.
|
||||
|
||||
**Решение:** добавить JS-функцию `validateClientIP()` в EJS-шаблон:
|
||||
- Проверка приватных/запрещённых диапазонов (показывать ошибку сразу)
|
||||
- Предпросмотр нормализации («будет сохранено как X.X.X.0/24»)
|
||||
|
||||
**Файлы:** `views/index.ejs`.
|
||||
|
||||
---
|
||||
|
||||
## 4. §5 — Уведомление о нормализации в UI
|
||||
|
||||
**Проблема:** API возвращает `wasNormalized`, но UI может не показывать.
|
||||
|
||||
**Решение:** проверить `ui/routes/entries.js` — передаёт ли `wasNormalized` в шаблон.
|
||||
Если нет — добавить. В шаблоне показать жёлтый alert.
|
||||
|
||||
**Файлы:** `ui/routes/entries.js`, `views/index.ejs`.
|
||||
|
||||
---
|
||||
|
||||
## Порядок:
|
||||
1. §4.7 — самая простая, одна строка
|
||||
2. §5 — уведомление о нормализации
|
||||
3. §5 — клиентская валидация
|
||||
4. §4.1 — фильтр удалённых (самая объёмная)
|
||||
5. Везде: тесты, VERSION++, коммит
|
||||
@@ -1,110 +0,0 @@
|
||||
# Чистка кластеров — 01.06.2026
|
||||
|
||||
## Кластер: iot-naeel (5.172.178.213)
|
||||
|
||||
### Удалено
|
||||
|
||||
| Группа | Штук | Причина |
|
||||
|---|---|---|
|
||||
| `fission-test-*` | 27 | Тестовые Fission namespace-ы с подами. Жрали ~24 CPU limits |
|
||||
| `fission-*` (с хешами) | 40 | Остатки Fission environment-ов. Сначала удалились, потом воссоздались через CRD — потребовалось удалить CRD `environments.fission.io` |
|
||||
| `bench-func-*` | 6 | Пустые bench namespace-ы |
|
||||
| `testns` | 1 | Пустой тестовый namespace |
|
||||
| `fission` (ядро, helm) | 1 | `helm uninstall fission -n fission` |
|
||||
| `fission-functions` | 1 | Пустой |
|
||||
| CRD Fission | 8 | `canaryconfigs, environments, functions, httptriggers, kuberneteswatchtriggers, messagequeuetriggers, packages, timetriggers` |
|
||||
|
||||
### Итого удалено: ~84 namespace-а + 8 CRD
|
||||
|
||||
### Ресурсы после чистки
|
||||
|
||||
| Нода | CPU req | CPU limits | MEM limits |
|
||||
|---|---|---|---|
|
||||
| `6f74n` | 19% | 97% | 36% |
|
||||
| `sc8p5` | 19% | 115% | 39% |
|
||||
| `v8zq4` | 20% | 126% | 55% |
|
||||
|
||||
**Свободно: ~19 ядер, ~41 Gi памяти**
|
||||
|
||||
---
|
||||
|
||||
## Кластер: naeel-test-3 (185.247.187.146)
|
||||
|
||||
### Удалено
|
||||
|
||||
| Группа | Штук | Причина |
|
||||
|---|---|---|
|
||||
| `sless-fn-cmp-op-*` | 20 | Пустые namespace-ы, 52 дня |
|
||||
| `sless-fn-test001` | 1 | SQS test, воссоздавался через `queueservice.sqs.kube5s.ru` CRD — удалили CRD `test-tenant-001` |
|
||||
| `sless-fn-test002` | 1 | Пустой |
|
||||
| `sless-16367aacb67a4a01` | 1 | Пустой |
|
||||
| `sless-fn-timing-ts` | 1 | SQS timing. Удалён CRD `test-tenant-timing-ts` + namespace |
|
||||
| `sless` | 1 | IoT платформа (Kafka OOMKilled, 100 рестартов) |
|
||||
| `shared-sqs` | 1 | SQS consumer |
|
||||
| `sqs-operator-system` | 1 | SQS оператор |
|
||||
| `1dbfe9da-...` | 1 | RabbitMQ managed |
|
||||
|
||||
### Починено: metrics-server
|
||||
|
||||
Проблема: 0/1 Ready 70 дней. Три бага платформы shturval:
|
||||
|
||||
1. **TLS**: kubelet-сертификаты без IP SANs → `--kubelet-insecure-tls`
|
||||
2. **readOnlyRootFilesystem**: не может создать `/apiserver.local.config` → `--cert-dir=/tmp` + `volumeMount: /tmp`
|
||||
3. **runAsNonRoot 1000**: порт 443 недоступен → `--secure-port=4443` + пробы HTTP:4443 + сервис `targetPort: 4443`
|
||||
|
||||
Итоговый deployment metrics-server:
|
||||
```yaml
|
||||
args:
|
||||
- --kubelet-insecure-tls
|
||||
- --kubelet-preferred-address-types=InternalIP
|
||||
- --cert-dir=/tmp
|
||||
- --secure-port=4443
|
||||
volumeMounts:
|
||||
- mountPath: /tmp
|
||||
name: tmp-dir
|
||||
volumes:
|
||||
- name: tmp-dir
|
||||
emptyDir: {}
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /readyz
|
||||
port: 4443
|
||||
scheme: HTTP
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /livez
|
||||
port: 4443
|
||||
scheme: HTTP
|
||||
```
|
||||
|
||||
Service `metrics-server`:
|
||||
```yaml
|
||||
ports:
|
||||
- port: 443
|
||||
targetPort: 4443
|
||||
```
|
||||
|
||||
### Lucee
|
||||
|
||||
- Задеплоен в namespace `3d7657ee-...` → 1/1 Ready
|
||||
- Домен: `lucee-mfysayo333` (ошибка была `lucee-mysayo333`)
|
||||
- Платформа: `naeel-test-3`
|
||||
- git: `https://github.com/xahys/testlucee`
|
||||
- jsonEnv: оставлен пустым (формат KEY=VALUE, не JSON)
|
||||
|
||||
### Ресурсы после чистки (worker-ноды, 12 ядер total)
|
||||
|
||||
| Нода | CPU req | MEM req |
|
||||
|---|---|---|
|
||||
| `vxzch` | 6% | 7% |
|
||||
| `wwqj2` | 30% | 25% |
|
||||
| `zxnb4` | 37% | 29% |
|
||||
|
||||
---
|
||||
|
||||
## Важные уроки
|
||||
|
||||
1. **Fission**: Недостаточно `kubectl delete ns` — нужно сначала удалить CRD `environments`, иначе poolmgr воссоздаст namespace
|
||||
2. **SQS operator**: Недостаточно удалить namespace — нужно удалить CRD `queueservice` в `sqs-operator-system`
|
||||
3. **Удаление с finalizer**: Зависшие Terminating форсировать через `kubectl replace --raw /api/v1/namespaces/$ns/finalize`
|
||||
4. **metrics-server от shturval**: Имеет три бага из коробки, несовместим с security policy платформы
|
||||
@@ -1,51 +0,0 @@
|
||||
# Деплой на ВМ (отладка)
|
||||
|
||||
> 2026-06-02. Временное решение пока NodeJS-платформа не готова.
|
||||
|
||||
## Git — без изменений
|
||||
|
||||
Локально → `git add` + `git commit` + `git push` → gitea.services.ngcloud.ru/Nail/ipwhitelist-app.git
|
||||
|
||||
## Схема деплоя
|
||||
|
||||
```
|
||||
Локально (правки) → git push → gitea
|
||||
↓
|
||||
git pull на ВМ
|
||||
↓
|
||||
pm2 restart ipwhitelist
|
||||
↓
|
||||
https://italo.kube5s.ru (nginx → :3000)
|
||||
```
|
||||
|
||||
## ВМ
|
||||
|
||||
- IP: `5.172.178.213`
|
||||
- SSH: `ssh -i ~/.ssh/naeel_vm_id_ed25519 naeel@5.172.178.213`
|
||||
- Nginx: `/etc/nginx/conf.d/italo.kube5s.ru.conf` → `proxy_pass http://127.0.0.1:3000`
|
||||
- PM2: `pm2 start server.js --name ipwhitelist`
|
||||
|
||||
## PostgreSQL
|
||||
|
||||
Локальный на ВМ. `.env`: `DB_HOST=localhost`.
|
||||
|
||||
## Отличия от боевого деплоя
|
||||
|
||||
| Параметр | ВМ (отладка) | K8s (бой) |
|
||||
|---|---|---|
|
||||
| DB_HOST | `localhost` | `postgresqlk8s-master...svc.cluster.local` |
|
||||
| Аутентификация | Mock (DEV_MODE=true) | OIDC Keycloak |
|
||||
| URL | `https://italo.kube5s.ru` | `https://wipl...` (платформа) |
|
||||
| SSL | Let's Encrypt (kube5s.ru) | Платформа |
|
||||
| Деплой | rsync + git pull | Платформа (git clone) |
|
||||
|
||||
## Передача заказчику
|
||||
|
||||
После отладки:
|
||||
1. Репа: `https://gitea.services.ngcloud.ru/Nail/ipwhitelist-app.git`
|
||||
2. Схема БД: `sql/schema.sql`
|
||||
3. Документация: `docs/`
|
||||
- `ТЗ.md` — техзадание
|
||||
- `ТЗ-плюс.md` — уточнения
|
||||
- `keycloak-auth-reference.md` — OIDC-интеграция
|
||||
4. Тесты: `node tests/api.js` (121 тест)
|
||||
@@ -1,112 +0,0 @@
|
||||
# Дизайн-система платформы Nubes
|
||||
|
||||
> Извлечено из сохранённой страницы `h.h` (deck-test.ngcloud.ru)
|
||||
|
||||
---
|
||||
|
||||
## Сетка и контейнеры
|
||||
|
||||
| Элемент | Класс | Описание |
|
||||
|---|---|---|
|
||||
| Страница | `navigation:flex`, `services:grid` | Flex/grid на всём |
|
||||
| Карточка | `ui-kit:bg-card ui-kit:rounded-xl ui-kit:border ui-kit:shadow-sm` | Белая карточка, border-radius 12px |
|
||||
| Заголовок карточки | `ui-kit:bg-brand-grey-light ui-kit:px-3 ui-kit:py-3` | Серый фон `#f3f4f6`, padding 12px |
|
||||
| Тело карточки | `ui-kit:px-3 ui-kit:py-3` | padding 12px |
|
||||
|
||||
---
|
||||
|
||||
## Цвета (переменные)
|
||||
|
||||
| Переменная | Назначение | Примерный HEX |
|
||||
|---|---|---|
|
||||
| `--brand-primary` | Основной цвет | `#2563eb` (синий) |
|
||||
| `--brand-gray` | Цвет границ | `#d1d5db` |
|
||||
| `--brand-grey-light` | Фон заголовков | `#f3f4f6` |
|
||||
| `--brand-primary-dark` | Ховер ссылок | `#1d4ed8` |
|
||||
|
||||
---
|
||||
|
||||
## Формы
|
||||
|
||||
```
|
||||
form-table (класс services:):
|
||||
grid-template-columns: fit-content(200px) minmax(200px, 1fr) 0px
|
||||
gap: 8px 16px
|
||||
```
|
||||
|
||||
| Элемент | Класс | Стиль |
|
||||
|---|---|---|
|
||||
| Лейбл | `ui-kit:text-sm ui-kit:leading-none ui-kit:font-normal ui-kit:mb-1 ui-kit:ml-1` | 14px, sans-serif, отступ слева |
|
||||
| Инпут | `ui-kit:h-9 ui-kit:rounded-md ui-kit:border ui-kit:px-3 ui-kit:text-sm` | h=36px, border, padding |
|
||||
| Текстареа | `ui-kit:rounded-md ui-kit:border ui-kit:px-3 ui-kit:py-2 ui-kit:text-sm` | авто-height |
|
||||
|
||||
---
|
||||
|
||||
## Кнопки
|
||||
|
||||
| Тип | Стиль | Класс |
|
||||
|---|---|---|
|
||||
| Обычная | border, bg-white, hover:bg-accent | `ui-kit:border ui-kit:bg-background ui-kit:h-8 ui-kit:rounded-md` |
|
||||
| Удалить | bg-destructive, text-white | `ui-kit:bg-destructive ui-kit:text-white` |
|
||||
| Иконка | size-5 | `ui-kit:size-5 ui-kit:cursor-pointer` |
|
||||
|
||||
Все кнопки: `ui-kit:h-8 ui-kit:rounded-md ui-kit:gap-1.5 ui-kit:px-3`, 14px шрифт.
|
||||
|
||||
---
|
||||
|
||||
## Таблицы
|
||||
|
||||
| Элемент | Стиль |
|
||||
|---|---|
|
||||
| Обёртка | `ui-kit:rounded-md ui-kit:border ui-kit:overflow-hidden` |
|
||||
| Шапка (th) | `ui-kit:bg-brand-grey-light`, uppercase, `ui-kit:py-1 ui-kit:px-2`, border-right |
|
||||
| Ячейка (td) | `ui-kit:px-2 ui-kit:py-1`, border-right, border-bottom |
|
||||
| Строка (tr) | `ui-kit:border-b ui-kit:border-brand-gray-8`, hover: `ui-kit:bg-brand-grey-light/50` |
|
||||
|
||||
---
|
||||
|
||||
## Иконки
|
||||
|
||||
Используются: **Lucide** (`lucide-*`)
|
||||
|
||||
Часто используемые:
|
||||
- `lucide-square-pen` — редактировать
|
||||
- `lucide-rotate-cw` — перезапустить
|
||||
- `lucide-trash` — удалить
|
||||
- `lucide-pause` — остановить
|
||||
- `lucide-play` — запустить
|
||||
- `lucide-save` — сохранить
|
||||
- `lucide-x` — закрыть
|
||||
- `lucide-copy` — копировать
|
||||
- `lucide-check` — успех (зелёный)
|
||||
- `lucide-x` — ошибка (красный)
|
||||
|
||||
---
|
||||
|
||||
## Типографика
|
||||
|
||||
- Основной шрифт: system-ui (Segoe UI, Roboto, etc.)
|
||||
- Размер: `text-sm` = 14px, `text-base` = 16px
|
||||
- Межстрочный: `leading-none` (1), `leading-normal` (1.5)
|
||||
- Цвет текста: `#1a1a1a`
|
||||
- Muted: `text-muted-foreground` = серый `#6b7280`
|
||||
- Заголовки карточек: `font-semibold`, 16px
|
||||
|
||||
---
|
||||
|
||||
## Навигация (слева)
|
||||
|
||||
- Ширина: `var(--sidebar-width)` = 12rem (192px)
|
||||
- Свёрнуто: `var(--sidebar-width-icon)` = 4.5rem (72px)
|
||||
- Верхняя панель: h-20 (80px), border-t-4 border-t-blue-500
|
||||
- Лого: инлайн SVG, 150px ширина
|
||||
|
||||
---
|
||||
|
||||
## Состояния
|
||||
|
||||
| Статус | Цвет |
|
||||
|---|---|
|
||||
| Успех / running | `text-green-500` + иконка `lucide-check` |
|
||||
| Ошибка | `text-red-500` + иконка `lucide-x` |
|
||||
| Предупреждение | `text-amber-500` |
|
||||
@@ -1,61 +0,0 @@
|
||||
#!/bin/bash
|
||||
# API-тесты: все комбинации (без UI)
|
||||
# Запуск: bash docs/test-api.sh
|
||||
|
||||
BASE="https://white.nodejsk8s.dev.nubes.ru"
|
||||
PASS=0
|
||||
FAIL=0
|
||||
|
||||
green() { echo -e "\033[32m$1\033[0m"; }
|
||||
red() { echo -e "\033[31m$1\033[0m"; }
|
||||
|
||||
check() { # check "описание" expected actual
|
||||
if [ "$2" = "$3" ]; then
|
||||
green " ✓ $1"
|
||||
PASS=$((PASS+1))
|
||||
else
|
||||
red " ✗ $1 (ожидалось: $2, получено: $3)"
|
||||
FAIL=$((FAIL+1))
|
||||
fi
|
||||
}
|
||||
|
||||
# ── Получить mock JWT для заданного clientId ───────────────────
|
||||
get_token() {
|
||||
local CLIENT_ID="$1"
|
||||
# POST /dev-login для получения токена через API
|
||||
# Возвращает access_token из ответа
|
||||
local RESP=$(curl -s -c /tmp/jar-test.txt "$BASE/login" > /dev/null && \
|
||||
curl -s -b /tmp/jar-test.txt -c /tmp/jar-test.txt \
|
||||
-X POST "$BASE/login" \
|
||||
-d "clientId=$CLIENT_ID" \
|
||||
-D - 2>&1)
|
||||
# Извлечь токен из редиректа (он в сессии, получаем через API)
|
||||
# Используем /dev-login для прямого получения токена
|
||||
local CSRF=$(curl -s -b /tmp/jar-test.txt "$BASE/dev-login" | grep -oP 'name="_csrf" value="\K[^"]+')
|
||||
curl -s -b /tmp/jar-test.txt -c /tmp/jar-test.txt \
|
||||
-X POST "$BASE/dev-login" \
|
||||
-d "clientId=$CLIENT_ID&_csrf=$CSRF&email=test@test.local&companyName=TestCo" \
|
||||
> /dev/null
|
||||
# Получить api-токен через сессию
|
||||
# Пробуем получить через /login page (там токен генерится в сессию)
|
||||
# Возвращаем токен из cookie
|
||||
echo "TODO"
|
||||
}
|
||||
|
||||
echo "========================================="
|
||||
echo " API Tests v0.5.4"
|
||||
echo "========================================="
|
||||
echo ""
|
||||
|
||||
# ── 1. Без токена → 401 ────────────────────────────────────────
|
||||
echo "--- 1. No token → 401 ---"
|
||||
CODE=$(curl -s -o /dev/null -w '%{http_code}' "$BASE/api/v1/entries")
|
||||
check "GET /entries без токена" "401" "$CODE"
|
||||
|
||||
CODE=$(curl -s -o /dev/null -w '%{http_code}' -X POST "$BASE/api/v1/entries" -H 'Content-Type: application/json' -d '{"value":"1.1.1.1/32"}')
|
||||
check "POST /entries без токена" "401" "$CODE"
|
||||
|
||||
echo ""
|
||||
echo "========================================="
|
||||
echo " Результат: $PASS/$((PASS+FAIL))"
|
||||
echo "========================================="
|
||||
@@ -1,104 +0,0 @@
|
||||
# Тесты: мульти-компания (2026-06-02)
|
||||
|
||||
> Запускать против `https://white.nodejsk8s.dev.nubes.ru`
|
||||
> Куки сохраняются между запросами (использовать `-c jar.txt -b jar.txt`)
|
||||
|
||||
## 1. Логин под мульти-компанией
|
||||
|
||||
```bash
|
||||
# Получить CSRF-токен и логин-форму
|
||||
curl -s -c jar.txt https://white.nodejsk8s.dev.nubes.ru/login > /dev/null
|
||||
|
||||
# Извлечь CSRF-токен
|
||||
CSRF=$(curl -s -b jar.txt https://white.nodejsk8s.dev.nubes.ru/login | grep -oP 'name="_csrf" value="\K[^"]+')
|
||||
|
||||
# Залогиниться как "multi"
|
||||
curl -s -b jar.txt -c jar.txt \
|
||||
-X POST https://white.nodejsk8s.dev.nubes.ru/login \
|
||||
-d "user=multi&_csrf=$CSRF" \
|
||||
-D - | head -1
|
||||
# Ожидаем: HTTP/1.1 302 → /
|
||||
|
||||
# Проверить что сессия содержит allClientIds
|
||||
curl -s -b jar.txt https://white.nodejsk8s.dev.nubes.ru/ | grep -c 'WZ01325'
|
||||
# Ожидаем: >0 (активная компания в интерфейсе)
|
||||
```
|
||||
|
||||
## 2. Переключатель компаний в UI
|
||||
|
||||
```bash
|
||||
# Страница должна содержать переключатель (<select name="switchTo">)
|
||||
curl -s -b jar.txt https://white.nodejsk8s.dev.nubes.ru/ | grep -c 'switchTo'
|
||||
# Ожидаем: >0
|
||||
|
||||
# Должны быть обе компании в options
|
||||
curl -s -b jar.txt https://white.nodejsk8s.dev.nubes.ru/ | grep -o 'WZ0[0-9]*'
|
||||
# Ожидаем: WZ01325 и WZ02001
|
||||
|
||||
# Переключиться на WZ02001
|
||||
curl -s -b jar.txt -c jar.txt \
|
||||
https://white.nodejsk8s.dev.nubes.ru/?switchTo=WZ02001 \
|
||||
> /dev/null
|
||||
|
||||
# Проверить что активная компания — WZ02001
|
||||
curl -s -b jar.txt https://white.nodejsk8s.dev.nubes.ru/ | grep -c 'WZ02001'
|
||||
# Ожидаем: >0
|
||||
```
|
||||
|
||||
## 3. Добавление записи в активную компанию
|
||||
|
||||
```bash
|
||||
# Создать запись в WZ02001 (после переключения на неё)
|
||||
CSRF=$(curl -s -b jar.txt https://white.nodejsk8s.dev.nubes.ru/ | grep -oP 'name="_csrf" value="\K[^"]+')
|
||||
|
||||
curl -s -b jar.txt -c jar.txt \
|
||||
-X POST https://white.nodejsk8s.dev.nubes.ru/add \
|
||||
-d "value=8.8.8.8/32&comment=multi-test&_csrf=$CSRF" \
|
||||
-D - | head -1
|
||||
# Ожидаем: HTTP/1.1 302
|
||||
|
||||
# Проверить что запись появилась в WZ02001
|
||||
curl -s -b jar.txt https://white.nodejsk8s.dev.nubes.ru/ | grep -c '8.8.8.8'
|
||||
# Ожидаем: >0
|
||||
```
|
||||
|
||||
## 4. Проверка изоляции компаний
|
||||
|
||||
```bash
|
||||
# Переключиться обратно на WZ01325
|
||||
curl -s -b jar.txt -c jar.txt \
|
||||
https://white.nodejsk8s.dev.nubes.ru/?switchTo=WZ01325 \
|
||||
> /dev/null
|
||||
|
||||
# Запись 8.8.8.8 из WZ02001 НЕ должна быть видна в WZ01325
|
||||
curl -s -b jar.txt https://white.nodejsk8s.dev.nubes.ru/ | grep -c '8.8.8.8'
|
||||
# Ожидаем: 0
|
||||
```
|
||||
|
||||
## 5. API Bearer-тест (опционально)
|
||||
|
||||
```bash
|
||||
# Выпустить mock JWT с clientid через запятую
|
||||
# (требует ручной JWT через /dev-login или issueMockToken)
|
||||
# Затем:
|
||||
curl -s -H "Authorization: Bearer <mock-jwt>" \
|
||||
https://white.nodejsk8s.dev.nubes.ru/api/v1/entries | jq .
|
||||
# Ожидаем: записи для первой компании (WZ01325)
|
||||
```
|
||||
|
||||
## 6. Негативные тесты
|
||||
|
||||
```bash
|
||||
# Переключение на несуществующую компанию — игнорируется
|
||||
curl -s -b jar.txt -c jar.txt \
|
||||
https://white.nodejsk8s.dev.nubes.ru/?switchTo=WZ99999 \
|
||||
> /dev/null
|
||||
|
||||
# Должен остаться на WZ01325
|
||||
curl -s -b jar.txt https://white.nodejsk8s.dev.nubes.ru/ | grep -c 'WZ01325'
|
||||
# Ожидаем: >0
|
||||
|
||||
# Одиночная компания (test, не multi) — переключателя быть не должно
|
||||
# Залогиниться как test и проверить:
|
||||
# grep -c 'switchTo' → ожидаем 0
|
||||
```
|
||||
@@ -1,5 +0,0 @@
|
||||
# research/
|
||||
|
||||
Материалы обратного инжиниринга платформы Nubes — анализ трафика, HAR, токены, схемы взаимодействия.
|
||||
|
||||
В отличие от `docs/` (проектная документация), здесь — результаты исследования внешних систем, которые мы не контролируем.
|
||||
@@ -1,209 +0,0 @@
|
||||
# SSO / Auth — исследование и контекст
|
||||
|
||||
> Дата: 2026-05-30
|
||||
> Актуально для ветки `sonnet`
|
||||
|
||||
---
|
||||
|
||||
## Исходные данные от команды
|
||||
|
||||
### Ссылки (получены 2026-05-30)
|
||||
|
||||
| Что | URL | Примечание |
|
||||
|---|---|---|
|
||||
| Пример SSO на ColdFusion | https://gitea.services.ngcloud.ru/smishchuk/payg-report.git | Написан «на коленке», но рабочий |
|
||||
| Конфигурация сервиса в Deck | https://deck.ngcloud.ru/services/instance/detail/523413d2-1ffd-457b-b0e3-0a8185fe9358 | Там видно как кладутся env-переменные |
|
||||
|
||||
### Файлы из payg-report сохранены локально
|
||||
|
||||
```
|
||||
research/payg-sso/
|
||||
Application.cfc — основной SSO flow (редирект, обмен code→token, refresh, logout)
|
||||
lib_oauth2.cfc — Authorization Code Flow клиент
|
||||
lib_jwt.cfc — валидация JWT RS256
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Keycloak — эндпоинты
|
||||
|
||||
Realm: `cloud`
|
||||
Base: `https://keycloak.nubes.ru/realms/cloud`
|
||||
|
||||
| Назначение | URL |
|
||||
|---|---|
|
||||
| Авторизация (браузер → KK) | `https://keycloak.nubes.ru/realms/cloud/protocol/openid-connect/auth` |
|
||||
| Обмен code → token | `https://keycloak.nubes.ru/realms/cloud/protocol/openid-connect/token` |
|
||||
| Logout | `https://keycloak.nubes.ru/realms/cloud/protocol/openid-connect/logout` |
|
||||
| JWKS (публичные ключи) | `https://keycloak.nubes.ru/realms/cloud/protocol/openid-connect/certs` |
|
||||
| OpenID конфигурация | `https://keycloak.nubes.ru/realms/cloud/.well-known/openid-configuration` |
|
||||
|
||||
---
|
||||
|
||||
## Реальная схема аутентификации
|
||||
|
||||
```
|
||||
Браузер
|
||||
│
|
||||
│ 1. GET / (без токена)
|
||||
▼
|
||||
наше приложение
|
||||
│
|
||||
│ 2. redirect → KK /auth?client_id=...&redirect_uri=...&scope=openid
|
||||
▼
|
||||
Keycloak (keycloak.nubes.ru, realm=cloud)
|
||||
│
|
||||
│ 3. Пользователь логинится
|
||||
│ 4. KK redirect → наш /callback?code=...
|
||||
▼
|
||||
наше приложение
|
||||
│
|
||||
│ 5. POST /token (code + client_secret) → access_token + refresh_token
|
||||
│ 6. Валидация JWT через JWKS (certs endpoint)
|
||||
│ 7. Извлечение claims из JWT → req.user
|
||||
▼
|
||||
Работаем: req.user.ClientID = "WZ01325" и тд
|
||||
```
|
||||
|
||||
**Важно из примера payg-report:**
|
||||
- Тип flow: Authorization Code Flow (не Implicit, не PKCE — обычный)
|
||||
- `client_secret` передаётся при обмене code→token (confidential client)
|
||||
- Сертификат берётся с JWKS endpoint при старте, кэшируется в application scope
|
||||
- При истечении части времени жизни — автоматический refresh через refresh_token
|
||||
|
||||
---
|
||||
|
||||
## JWT — структура токена
|
||||
|
||||
JWT выпускает **auth-api** (не Keycloak напрямую).
|
||||
Алгоритм: **RS256**.
|
||||
JWKS для валидации: из auth-api (уточнить URL у DevOps).
|
||||
|
||||
> ⚠️ В payg-report используют `keycloak.nubes.ru/certs`, но наш портал deck.ngcloud.ru
|
||||
> идёт через auth-api.ngcloud.ru — нужно уточнить чей именно JWT будет у нас.
|
||||
|
||||
### Claims в JWT (из реального токена, secrets.txt)
|
||||
|
||||
| Claim | Тип | Пример | Назначение |
|
||||
|---|---|---|---|
|
||||
| `iss` | string | `"auth-api"` | Издатель |
|
||||
| `sub` | string | `"0199e325-1cdf-..."` | UUID пользователя |
|
||||
| `exp` | number | `1795627443` | Срок действия |
|
||||
| `iat` | number | `1780075443` | Выпущен |
|
||||
| `ClientID` | string | `"WZ01325"` | **WZ-номер компании** ← ключевой claim |
|
||||
| `company_id` | string (UUID) | `"3e64aac6-dcfc-..."` | UUID компании |
|
||||
| `company_name` | string | `"Тест"` | Название компании |
|
||||
| `email` | string | `"tazet@narod.ru"` | Email (для аудита) |
|
||||
| `login` | string | `"tazet@narod.ru"` | Логин |
|
||||
| `firstname` | string | `"Наиль"` | Имя |
|
||||
| `lastname` | string | `"Тазетдинов"` | Фамилия |
|
||||
| `token_type` | string | `"tech"` | Тип токена |
|
||||
|
||||
**Пример декодированного payload** (из secrets.txt — не секрет, payload JWT не зашифрован):
|
||||
```json
|
||||
{
|
||||
"iss": "auth-api",
|
||||
"sub": "0199e325-1cdf-7cda-9319-e5302a85e291",
|
||||
"ClientID": "WZ01325",
|
||||
"company_id": "3e64aac6-dcfc-4082-88dc-da19c86555a5",
|
||||
"company_name": "Тест",
|
||||
"email": "tazet@narod.ru",
|
||||
"login": "tazet@narod.ru",
|
||||
"token_type": "tech"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Конфигурация сервиса (env-переменные)
|
||||
|
||||
Из примера payg-report и Deck — конфиги кладутся в переменные окружения:
|
||||
|
||||
```bash
|
||||
# Нужно получить от DevOps:
|
||||
KC_CLIENT_ID=white.nodejsk8s.dev.nubes.ru # имя нашего клиента в KK (уточнить)
|
||||
KC_CLIENT_SECRET=<секрет> # из Deck / у DevOps
|
||||
JWKS_URL=https://keycloak.nubes.ru/realms/cloud/protocol/openid-connect/certs
|
||||
# ИЛИ если через auth-api:
|
||||
# JWKS_URL=https://auth-api.ngcloud.ru/.well-known/jwks.json
|
||||
|
||||
# В payg-report переменная называется:
|
||||
IDP_CLIENT_SECRET=<секрет>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Что сейчас в нашем коде
|
||||
|
||||
Файл: `src/auth.js`
|
||||
|
||||
| Режим | Условие | Поведение |
|
||||
|---|---|---|
|
||||
| **DEV_MODE** | `DEV_MODE=true` и не production | Авторизация пропущена, юзер захардкожен из `MOCK_USERS` |
|
||||
| **JWKS_URL задан** | `JWKS_URL != ''` | Валидирует Bearer-токен из заголовка через JWKS |
|
||||
| **Мок RS256** | Ничего из выше | Генерирует собственную RSA-пару, выдаёт и валидирует JWT сам |
|
||||
|
||||
**Чего не хватает для продакшена:**
|
||||
- Authorization Code Flow (редирект на KK и обратно)
|
||||
- Обмен `code` → `access_token` через `/token`
|
||||
- Session/cookie для хранения токена между запросами
|
||||
- Refresh токена
|
||||
|
||||
---
|
||||
|
||||
## Пример SSO flow из payg-report (ключевые строки)
|
||||
|
||||
```javascript
|
||||
// Настройка (из окружения):
|
||||
const client_id = process.env.IDP_CLIENT_SECRET; // их название
|
||||
const auth_endpoint = 'https://keycloak.nubes.ru/realms/cloud/protocol/openid-connect/auth';
|
||||
const token_endpoint = 'https://keycloak.nubes.ru/realms/cloud/protocol/openid-connect/token';
|
||||
const certs_url = 'https://keycloak.nubes.ru/realms/cloud/protocol/openid-connect/certs';
|
||||
|
||||
// 1. Нет сессии → redirect на KK:
|
||||
location(idp.buildRedirectToAuthURL({scope: 'openid profile email', state: guid}));
|
||||
|
||||
// 2. KK вернул ?code=... → меняем на токен:
|
||||
const resp = idp.makeAccessTokenRequest(url.code);
|
||||
|
||||
// 3. Парсим JWT из ответа:
|
||||
const token_data = jwt.decode(resp.access_token, idpCertificate, 'RS256');
|
||||
session.auth.wz = token_data.ClientID; // WZ-номер компании
|
||||
session.auth.login = token_data.preferred_username;
|
||||
|
||||
// 4. Refresh когда прошло > 2/3 времени жизни (только на GET):
|
||||
if (timeSinceIat > refresh_expires_in / 1.5 && method === 'GET') {
|
||||
const resp = idp.refreshAccessTokenRequest(session.auth.refresh_token);
|
||||
// ... обновляем сессию
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Открытые вопросы (нужен ответ от DevOps/KK-команды)
|
||||
|
||||
| # | Вопрос | Влияет на |
|
||||
|---|---|---|
|
||||
| 1 | Какой `client_id` выдан нашему сервису в KK realm `cloud`? | Конфиг |
|
||||
| 2 | Где взять `client_secret`? | Конфиг |
|
||||
| 3 | Токен от KK или от auth-api? Соответственно — какой JWKS_URL? | `src/auth.js` |
|
||||
| 4 | Claim для admin-роли: чек-бокс — это `realm_roles`, `resource_access`, attribute? | `src/auth.js` requireAdmin |
|
||||
| 5 | `ClientID` в токене — строка или массив (multi-company)? | `src/queries.js`, UI |
|
||||
| 6 | `/export` — нужна ли авторизация или только сетевое ограничение по IP? | `src/routes/export.js` |
|
||||
|
||||
---
|
||||
|
||||
## API Gateway (для справки)
|
||||
|
||||
Из `docs/auth-architecture.md`:
|
||||
- Gateway: `lk-api-gateway.ngcloud.ru`
|
||||
- JWT из localStorage портала: `authApiTokens.access_token`
|
||||
- **DDOS-Guard cookies обязательны** при curl-тестировании: `__ddg1_`, `__ddg8_`, `__ddg9_`, `__ddg10_`
|
||||
|
||||
```bash
|
||||
# Пример рабочего curl (2026-05-29):
|
||||
curl -H "Authorization: Bearer <JWT>" \
|
||||
-H "Origin: https://deck.ngcloud.ru" \
|
||||
-H "Cookie: __ddg1_=...; __ddg8_=...; __ddg9_=...; __ddg10_=..." \
|
||||
"https://lk-api-gateway.ngcloud.ru/api/v1/..."
|
||||
```
|
||||
@@ -1,11 +0,0 @@
|
||||
<hr/>
|
||||
test
|
||||
<hr/>
|
||||
<cfflush/>
|
||||
<!--- <cftry>
|
||||
<cfdump var=#session#/>
|
||||
<cfcatch type="any"><cfdump var=#cfcatch#/></cfcatch>
|
||||
</cftry> --->
|
||||
|
||||
<cfmodule template="mod/crm_contract.cfm" wz="WZ01348"/>
|
||||
<cfdump var=#qComponent#/>
|
||||
@@ -1,522 +0,0 @@
|
||||
<cfcomponent
|
||||
displayname="Application"
|
||||
output="true"
|
||||
hint="Handle the application.">
|
||||
|
||||
|
||||
<!--- Pseudoconstructor --->
|
||||
<!--- Set up the application. --->
|
||||
<cfset this.Name = "PAYG-REPORT" />
|
||||
<cfset this.applicationTimeout = createTimeSpan( 0, 3, 0, 0 ) />
|
||||
<cfset this.sessionmanagement="Yes"/>
|
||||
<cfset this.clientmanagement="No"/>
|
||||
<cfset this.sessiontimeout=CreateTimeSpan(0, 1, 0, 0)/>
|
||||
<cfset this.setclientcookies="No"/>
|
||||
<cfset this.mappings = structNew() />
|
||||
<cfset this.mappings["/mod"] = getDirectoryFromPath(getCurrentTemplatePath()) & "mod/" />
|
||||
<cfset this.customTagPaths = expandPath(getDirectoryFromPath(getCurrentTemplatePath()) & "mod")/>
|
||||
<!--- <cfset this.nullSupport = true/> --->
|
||||
|
||||
<!--- SSO --->
|
||||
<cfset this.client_id = "payg-report.deck.nubes.ru"/>
|
||||
<cfset this.auth_endpoint = "https://keycloak.nubes.ru/realms/cloud/protocol/openid-connect/auth" />
|
||||
<cfset this.logout_endpoint = "https://keycloak.nubes.ru/realms/cloud/protocol/openid-connect/logout" />
|
||||
<cfset this.access_token_endpoint = "https://keycloak.nubes.ru/realms/cloud/protocol/openid-connect/token" />
|
||||
<cfset this.idpCertUrl = "https://keycloak.nubes.ru/realms/cloud/protocol/openid-connect/certs" />
|
||||
<cfset this.client_secret = createObject("java", "java.lang.System").getEnv("IDP_CLIENT_SECRET")/>
|
||||
<cfset this.iam_url = "https://auth-api.ngcloud.ru/api/v1/auth/user"/>
|
||||
<cfset this.redirect_uri = "https://#CGI.SERVER_NAME##CGI.SCRIPT_NAME#"/><!--- куда возвращаться от IDP --->
|
||||
|
||||
<cfset this.datasource = "rpt"/><!--- к буферной базе --->
|
||||
<cfset this.defaultdatasource = this.datasource/>
|
||||
<!--- request scope is available in pseudoconstructor
|
||||
see also https://www.bennadel.com/blog/1437-coldfusion-scope-existence-during-various-request-types-and-events.htm --->
|
||||
<cfset request.DS = "#this.datasource#"/>
|
||||
<cfset request.language=""/>
|
||||
<cfset getDS(this.datasource)/>
|
||||
<!--- кажется, нужно инициализировать датасорцы в псевдоконструкторе - onRequest не получается --->
|
||||
<!--- *** проверить, что есть - если есть, не создавать --->
|
||||
|
||||
|
||||
|
||||
<cffunction
|
||||
name="OnApplicationStart"
|
||||
access="public"
|
||||
returntype="boolean"
|
||||
output="false"
|
||||
hint="Fires when the application is first created.">
|
||||
|
||||
<!--- *** мы не проверяем срок жизни сертификата и его отзыв--->
|
||||
<!--- Obtain idp certificate OnApplicationStart --->
|
||||
<cfset application.idpCertificate = getIdpCertificate(this.idpCertUrl)/>
|
||||
<cfreturn true />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction
|
||||
name="OnRequest"
|
||||
access="public"
|
||||
returntype="void"
|
||||
output="true"
|
||||
hint="Fires after pre page processing is complete.">
|
||||
|
||||
<cfargument name="template" type="string" required="true"/>
|
||||
|
||||
<cfset request.startTickCount=getTickCount()/>
|
||||
|
||||
<cfset setEncoding("FORM", "UTF-8")>
|
||||
<cfset setEncoding("URL", "UTF-8")>
|
||||
|
||||
<cfset request.PERMISSION_NONE=0/>
|
||||
<cfset request.PERMISSION_READ=1/>
|
||||
<cfset request.PERMISSION_WRITE=2/>
|
||||
|
||||
<!--- <cfset request.UNDEFINED_USR_ID=-1/>
|
||||
<cfset request.ANONYMOUS_USR_ID=2/>
|
||||
<cfset request.GUEST_USR_ID=3/> --->
|
||||
|
||||
<!--- global settings --->
|
||||
<cfset request.RECORDS_PER_PAGE=500/>
|
||||
<cfset request.APP_VERSION="0.00.020"/>
|
||||
<cfheader name="X-Application-Version" value=#request.APP_VERSION#/>
|
||||
<cfset request.STAND=getStand()/>
|
||||
|
||||
<!--- application constants --->
|
||||
|
||||
<!---<cfset request.SMTP_SERVER="172.16.16.16"/>
|
||||
<cfset request.MAIL_FROM_FOR_NOTIFICATION="Pipeline tracker <pipeline@mail.ru>"/>
|
||||
<cfset request.SUBJECT_PREFIX="[PIPELINE TRACKER] "/>--->
|
||||
<!---<cfset request.BASE_URL="https://smtest.dtln.local/pipeline/"/>*** сделать нормально. Внимание! При наличии прокси CGI.SERVER_NAME может быть заменено --->
|
||||
|
||||
<cfset local = {} />
|
||||
|
||||
<cfset local.basePath = getDirectoryFromPath(
|
||||
getCurrentTemplatePath()
|
||||
) />
|
||||
|
||||
<cfset local.targetPath = getDirectoryFromPath(
|
||||
expandPath( arguments.template )
|
||||
) />
|
||||
|
||||
<cfset local.requestDepth = (
|
||||
listLen( local.targetPath, "\/" ) -
|
||||
listLen( local.basePath, "\/" )
|
||||
) />
|
||||
|
||||
<cfset request.webRoot = repeatString(
|
||||
"../",
|
||||
local.requestDepth
|
||||
) />
|
||||
|
||||
<!---
|
||||
While we wouldn't normally do this for every page
|
||||
request (it would normally be cached in the
|
||||
application initialization), I'm going to calculate
|
||||
the site URL based on the web root.
|
||||
--->
|
||||
<cfset request.siteUrl = (
|
||||
IIF(
|
||||
(CGI.server_port_secure <!--- CGI.https EQ "On" does not work with apache+tomcat and nginx+tomcat --->),
|
||||
DE( "https://" ),
|
||||
DE( "http://" )
|
||||
) &
|
||||
cgi.http_host &
|
||||
reReplace(
|
||||
getDirectoryFromPath( arguments.template ), "([^\\/]+[\\/]){#local.requestDepth#}$",
|
||||
"",
|
||||
"one"
|
||||
)
|
||||
) />
|
||||
|
||||
<cfset request.thisPage=Replace(ReplaceNoCase(expandPath(ARGUMENTS.template), local.basePath, ""), "\", "/")/>
|
||||
<!--- <cfset request.thisUrl="#request.thisPage##len(CGI.queryString)#"/> чревато циклом --->
|
||||
|
||||
<!--- получение сертификата может занимать длительное время.
|
||||
Блокировать на это время приложение или сессию не следует.
|
||||
Вообще не следует ничего блокировать на время сетевого взаимодействия
|
||||
Нижеследующая, на первый взгляд, странная конструкция ровно для этого придумана
|
||||
--->
|
||||
<!--- <cfoutput>onRequest:check for cert started #(getTickCount()-request.startTickCount)#</cfoutput> --->
|
||||
<cfset var idpCertificateExists = false/>
|
||||
<cflock scope="application" type="readonly" timeout=1>
|
||||
<cfset request.APP_NAME=this.Name/>
|
||||
<cfset idpCertificateExists = structKeyExists(application,"idpCertificate")/>
|
||||
</cflock>
|
||||
|
||||
<cfif NOT idpCertificateExists>
|
||||
<!--- Obtain IDP Certificate (onRequest) --->
|
||||
<cfset var idpCertificate = getIdpCertificate(this.idpCertUrl) />
|
||||
<cflock scope="application" type="exclusive" timeout=1>
|
||||
<cfset application.idpCertificate = idpCertificate/>
|
||||
</cflock>
|
||||
</cfif>
|
||||
<!--- <cfoutput>onRequest:check for cert finished #(getTickCount()-request.startTickCount)#</cfoutput> --->
|
||||
|
||||
|
||||
|
||||
|
||||
<cfif structKeyExists(url,"logout")>
|
||||
<cflock scope="session" type="exclusive" timeout="3">
|
||||
<cfset structDelete(session, "auth")/>
|
||||
</cflock>
|
||||
</cfif>
|
||||
|
||||
<cfcookie name="CFID" value="#session.CFID#"/>
|
||||
<cfcookie name="CFTOKEN" value="#session.CFTOKEN#"/>
|
||||
|
||||
<cfinclude template="inc/functions.cfm"/>
|
||||
|
||||
<!--- SSO --->
|
||||
<!--- Если без сессии. Проверяем наличие токена в заголовке (и в куках?)
|
||||
Если его нет, идем к IDP за токеном. Получив токен, складываем его в куки
|
||||
Если токен есть, распаковываем его. Проверяем протухание. Если прошла установленная часть времени жизни, идем за рефрешем (внимание: это сработает только в браузере,
|
||||
если клиент не умеет редиректы - то токен должен быть достаточно свежий)
|
||||
(для начала делаем без рефреша, только проверяем протухание)
|
||||
А рефреш можно сделать на серверной стороне?
|
||||
Кладем данные из токена в реквест и наслаждаемся --->
|
||||
<!--- Вариант: если есть Authorization:bearer, идем с ним к IAM --->
|
||||
|
||||
<cfscript>
|
||||
|
||||
var requestData = GetHttpRequestData();
|
||||
var headers = requestData.headers;
|
||||
|
||||
if (structKeyExists(headers,"authorization")) { // аутентификация для клиента ЛК
|
||||
var authorizationHeader = headers.authorization;
|
||||
if (authorizationHeader.startsWith("Bearer ")) {
|
||||
var bearerToken = Mid(authorizationHeader, 8);
|
||||
writeDump(bearerToken);
|
||||
//var token=toString(binaryDecode(bearerToken, "base64"));
|
||||
//writeDump(token);
|
||||
//jwt = new lib.jwt(this.client_secret);
|
||||
//lock scope="application" type="readonly" timeout="1" {
|
||||
// var token_data = (jwt.decode(token, application.idpCertificate,"RS256"));
|
||||
//}
|
||||
var result="";
|
||||
//try {
|
||||
var iamService = new http(method = "GET", charset = "utf-8", url = #this.iam_url#, timeout="5");
|
||||
iamService.addParam(type = "HEADER", name = "Accept", value = "application/json");
|
||||
iamService.addParam(type = "HEADER", name = "Authorization", value = "#authorizationHeader#"); //passthrough
|
||||
//writedump(this.iamServiceUrl);abort;
|
||||
var resp = iamService.send();
|
||||
//if (resp.status_code NEQ 200) throw("IDP response not OK");
|
||||
//writedump(resp);abort;
|
||||
var prefix = resp.getPrefix();
|
||||
if (prefix.status_code NEQ 200) {
|
||||
//writedump(this.iamServiceUrl);
|
||||
//writedump(resp);
|
||||
var iamStatusCode = (isValid("integer", prefix.status_code)) ? val(prefix.status_code) : 500;
|
||||
throw(message="IAM error", detail="URL: #this.iam_url# Status Code: #prefix.status_code#");
|
||||
//abort;
|
||||
//throw("IDP response not OK");
|
||||
}
|
||||
result = prefix.filecontent;
|
||||
var idpUserData=deserializeJson(result);
|
||||
//request.auth.wz=idpUserData.userInfo.ClientId;//GUID!
|
||||
|
||||
|
||||
request.auth.login = idpUserData.userInfo.login;
|
||||
//request.usrUid=idpUserData.userInfo.contactId;//userId; //GUID!
|
||||
//writedump(idpUserData);abort;
|
||||
//} catch (e) {
|
||||
/*if (fileExists("#GetDirectoryFromPath(GetCurrentTemplatePath())#/etc/local-debug")) { //true for local debug without IDP, etc/* does not go to repository
|
||||
var result='{"accounts":[{"login":"","type":"telegram"}],"avatar":["d2d2b7ac-50af-432b-b7c4-f7d6561e288a"],"company":"ООО «НУБЕС»","companyId":"8ec70ac0-546d-42a7-8cff-339c8fb51a23","contactId":"983967a3-58c2-4cdd-84a5-8b427ccfac82","email":"smishchuk@nubes.ru","externalUser":false,"fio":{"fullName":"Мищук Сергей ","name":"Сергей","secondName":"","surname":"Мищук"},"groupIds":["94bf5be7-52f4-5c13-87c3-513786934685","ab12b6b8-0265-4683-a5c2-5e1a74a55216","aff008c3-7443-50f6-86e1-ecff3cd3b04d","d6000da0-c9aa-55eb-9882-f118b432730b","d89a33dc-3177-5854-9580-f7f860a5ab7c","ddfe2555-9ef4-42cb-9a2b-7f24e61e7747","df12926f-ecb8-5479-857f-6d291464baad","fda5c295-230a-5025-9797-b8b4e99e08aa","2be9b4b6-94d1-59f9-a649-cab228d82169","64fe6f5c-a91b-5fea-a7ca-d9823701ebd4"],"integration":{"serviceId":""},"login":"smishchuk@nubes.ru","mobilePhone":[],"position":"","userId":"d72530e1-66a4-412f-a046-38153c4e5405"}';}
|
||||
*/
|
||||
//writedump(resp);
|
||||
//return representationOf( {"exception"=e} );
|
||||
//rethrow(e);
|
||||
//}
|
||||
}
|
||||
} else {
|
||||
//точно мы так не словим дедлок ВПР
|
||||
lock scope="session" type="readonly" timeout="3" {
|
||||
if (structKeyExists(session, "auth")) {
|
||||
request.auth = structCopy(session.auth);
|
||||
}
|
||||
}
|
||||
if (structKeyExists(request, "auth") AND Now() < request.auth.exp) {
|
||||
|
||||
if (dateDiff("s", request.auth.iat, Now()) > request.auth.refresh_expires_in/1.5 AND CGI.REQUEST_METHOD EQ "GET") {
|
||||
// доля времени, после которой происходит рефреш, прибита гвоздями
|
||||
// По всей видимости, рефреш будет ломать обращения POSТ
|
||||
// В связи с чем предлагается дождаться GET
|
||||
// Приклеивать query_string как-то не пришлось, браузер сам справляется
|
||||
|
||||
// refresh
|
||||
var idp = new lib.oauth2(this.client_id, this.client_secret, this.auth_endpoint, this.access_token_endpoint, this.redirect_uri);
|
||||
var resp = idp.refreshAccessTokenRequest(request.auth.refresh_token);
|
||||
|
||||
lock scope="application" type="readonly" timeout="1" {
|
||||
idpCertificate = application.idpCertificate;
|
||||
}
|
||||
|
||||
var auth = parseIdpresponse(resp, idpCertificate, this.client_secret); //все эти сложности из-за опасений насчет многопоточности и блокировок
|
||||
|
||||
lock scope="session" type="exclusive" timeout="1" {
|
||||
session.auth = auth;
|
||||
}
|
||||
request.auth = auth;
|
||||
writeDump(auth);
|
||||
}
|
||||
} else {
|
||||
// сессии SSO нет
|
||||
// или токен протух
|
||||
request.auth_state = createGUID().toString();
|
||||
lock scope="session" type="exclusive" timeout="1" {
|
||||
structDelete(session, "auth"); // зачистили сессию от данных SSO
|
||||
session.auth_state = request.auth_state;
|
||||
}
|
||||
|
||||
var idp = new lib.oauth2(this.client_id, this.client_secret, this.auth_endpoint, this.access_token_endpoint, this.redirect_uri);
|
||||
/*
|
||||
часто появляется ошибка: после неудачного запроса к IDP
|
||||
в адресной строке браузера остается все, с чем его редиректил IDP,
|
||||
а повторный запрос с этим контентом уже не работает. Получаем 400 Bad Request -
|
||||
может быть, KeyCloak так защищается от циклических редиректов
|
||||
Не очень понятно, как предотвратить повторный запрос (можно, конечно, использовать сессию, но странно)
|
||||
*/
|
||||
//writeOutput(getTickCount()-request.startTickCount);
|
||||
if(structKeyExists(url, "code")) { //обрабатываем редирект от IDP *** наличие поля code в URL введет нас в заблуждение,
|
||||
|
||||
try {
|
||||
//writeOutput("idp.makeAccessTokenRequest");
|
||||
//writeOutput(getTickCount()-request.startTickCount);
|
||||
var resp = idp.makeAccessTokenRequest(url.code);
|
||||
|
||||
lock scope="application" type="readonly" timeout="1" {
|
||||
idpCertificate = application.idpCertificate;
|
||||
}
|
||||
|
||||
var auth = parseIdpresponse(resp, idpCertificate, this.client_secret); //все эти сложности из-за опасений насчет многопоточности и блокировок
|
||||
|
||||
lock scope="session" type="exclusive" timeout="1" {
|
||||
session.auth = auth;
|
||||
}
|
||||
//request.auth = auth;
|
||||
location(this.redirect_uri, false);
|
||||
} catch (e) {echo('<br>****************** #e.message# : #e.detail# **************');}
|
||||
|
||||
} else { //отправляем браузер к IDP
|
||||
var strURL =idp.buildRedirectToAuthURL({"scope":'openid profile email',"state":request.auth_state,"allow_signup":false});
|
||||
echo('<a href="#strURL#">self-made Auth link (idp) #strURL#</a> <br> <br>');
|
||||
location(strUrl,false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//request.logout_url = "";
|
||||
if (structKeyExists(request, "auth") AND structKeyExists(request.auth, "id_token")) {
|
||||
request.logout_url = "#this.logout_endpoint#?id_token_hint=#request.auth.id_token#&post_logout_redirect_uri=#this.redirect_uri#?logout";
|
||||
// внимание, здесь подразумевается, что redirect_uri не содержит query_string
|
||||
// после возвращения от IDP нам нужно будет зачистить сессию SSO, сделаем это по слову logout
|
||||
}
|
||||
|
||||
request.auth.wz='WZ01348'; //*******************
|
||||
</cfscript>
|
||||
|
||||
|
||||
<cfif structKeyExists(request, "auth")>
|
||||
<cfinclude template="#ARGUMENTS.template#"/>
|
||||
<cfelse>
|
||||
<cfset currentDir = (
|
||||
lCase(
|
||||
replace(
|
||||
getDirectoryFromPath(
|
||||
replaceNoCase(
|
||||
expandPath(
|
||||
ARGUMENTS.template
|
||||
),
|
||||
getDirectoryFromPath(
|
||||
getCurrentTemplatePath()
|
||||
),
|
||||
""
|
||||
)
|
||||
), "\", "/", "ALL"
|
||||
)
|
||||
)
|
||||
)/>
|
||||
<!--- <cfif currentDir EQ "saml/"><!--- note traling slash --->
|
||||
<cfinclude template="#ARGUMENTS.template#"/>
|
||||
<cfelse>
|
||||
<cfinclude template="login.cfm" />
|
||||
</cfif> --->
|
||||
</cfif>
|
||||
|
||||
|
||||
|
||||
<cfreturn />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction
|
||||
name="OnRequestEnd"
|
||||
access="public"
|
||||
returntype="void"
|
||||
output="true"
|
||||
hint="Fires after the page processing is complete.">
|
||||
<!--- Attention! Before CF9, OnrequestEnd is not executed in case of redirect. That is why we use session.save_login --->
|
||||
|
||||
<cfif structKeyExists(session, "save_login")>
|
||||
<cfif session.save_login EQ "">
|
||||
<!--- unset (expire) cookie --->
|
||||
<cfcookie expires="-1" name="portalUser" value="">
|
||||
<cfelse>
|
||||
<!--- set persistent cookie with no expiration --->
|
||||
<cfcookie expires="NEVER" name="portalUser" value="#encrypt(session.save_login,COOKIEENCKEY)#">
|
||||
</cfif>
|
||||
<cfset structDelete(session, "save_login")>
|
||||
</cfif>
|
||||
|
||||
<cfreturn />
|
||||
</cffunction>
|
||||
|
||||
<cffunction
|
||||
name="getStand"
|
||||
access="private"
|
||||
returntype="string"
|
||||
output="true"><!--- *** duplicated in svc-api --->
|
||||
|
||||
<cftry>
|
||||
<cfquery name=qConfig>
|
||||
select value as stand from config
|
||||
where name='STAND'
|
||||
</cfquery>
|
||||
<cfreturn qConfig.stand/>
|
||||
|
||||
<cfcatch type="ANY">
|
||||
<!--- do nothing, default will be returned --->
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
<cfreturn ""/>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction
|
||||
name="getDS"
|
||||
access="private"
|
||||
returntype="void"
|
||||
output="true"
|
||||
hint="Configure data source from environment variables (if datasource with the name provided already exists, does nothing). Convention: data source name is an environment varialble prefix">
|
||||
|
||||
<cfargument name="dsname" type="string" required="true"/>
|
||||
<cfargument name="prefix" type="string" default=#dsname#/>
|
||||
|
||||
<cftry>
|
||||
<cfquery name="qTestDs" datasource=#arguments.dsname#>
|
||||
select 1;
|
||||
</cfquery>
|
||||
|
||||
<cfcatch type="any">
|
||||
<cfset var ds={}/>
|
||||
<cfset var system = createObject("java", "java.lang.System")/>
|
||||
|
||||
<cfloop list="class,connectionString,database,driver,dbdriver,host,port,type,url,username,password,bundleName,bundleVersion,connectionLimit,liveTimeout,validate" item="field"><!--- driver vs dbdriver --->
|
||||
<cfset var value=system.getEnv("#arguments.prefix#_#field#")/>
|
||||
<cfif isDefined("value") AND len(value)>
|
||||
<cfset structInsert(ds,field,value)/>
|
||||
</cfif>
|
||||
</cfloop>
|
||||
<cfif structIsEmpty(ds)>
|
||||
<cfthrow type="application" message="Datasource not configured" detail="Datasource not defined in the environment. Expected prefix is #arguments.prefix#"/>
|
||||
</cfif>
|
||||
|
||||
<!--- test datasource (just to get exception if invalid) --->
|
||||
<cftry>
|
||||
<cfquery name="qTestDsNextTry" datasource=#ds#>
|
||||
select 2;
|
||||
</cfquery>
|
||||
|
||||
<cfcatch type="any">
|
||||
<!--- <cfdump var=#ds#/><cfabort/> --->
|
||||
<cfdump var=#arguments#/>
|
||||
<cfdump var=#ds#/>
|
||||
<cfrethrow/>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<cfset this.datasources["#arguments.dsname#"]=#ds#/> <!--- Интересно, доступен ли здесь this --->
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
<!--- <cfdump var=#ds#/> --->
|
||||
<cfreturn/>
|
||||
</cffunction>
|
||||
|
||||
<cfscript>
|
||||
//https://keycloak.nubes.ru/admin
|
||||
//https://keycloak.nubes.ru/realms/SSH_CA/account //smishchuk@mgmt.nubes.ru
|
||||
//https://stackoverflow.com/questions/28658735/what-are-keycloaks-oauth2-openid-connect-endpoints
|
||||
//http://https://keycloak.nubes.ru/realms/SSH_CA/.well-known/openid-configuration
|
||||
|
||||
//https://keycloak.nubes.ru/realms/cloud/.well-known/openid-configuration тут ссылка
|
||||
//https://keycloak.nubes.ru/realms/cloud/protocol/openid-connect/certs тут серт
|
||||
//только надо его обрамить -----BEGIN CERTIFICATE-----
|
||||
private function getIdpCertificate(certUrl) {
|
||||
|
||||
var httpService = new http();
|
||||
httpService.setMethod( "get" );
|
||||
httpService.setCharset( "utf-8" );
|
||||
httpService.setUrl(arguments.certUrl);
|
||||
|
||||
var result = httpService.send().getPrefix();
|
||||
var status_code = result.ResponseHeader['Status_Code'];
|
||||
|
||||
if ('200' == status_code) {
|
||||
var content = deserializeJson(result.FileContent);
|
||||
//мы подразумеваем структуру конкретно KeyCloak
|
||||
var key = "";
|
||||
for (key in content.keys) {
|
||||
if ("RSA" == key.kty AND "sig" == key.use) {
|
||||
return "-----BEGIN CERTIFICATE-----" & key.x5c[1] & "-----END CERTIFICATE-----";
|
||||
}
|
||||
}
|
||||
throw(message="RSA cetificate not found");
|
||||
} else {
|
||||
throw (message="Cannot obtain IDP certificate, request failed", detail="Status_Code #status_code#");
|
||||
}
|
||||
}
|
||||
|
||||
private struct function parseIdpResponse(struct resp, string certificate, string jwt_secret) {
|
||||
|
||||
var auth = structNew("linked");
|
||||
var data = deserializeJson(arguments.resp.content);
|
||||
var jwt = new lib.jwt(arguments.jwt_secret);
|
||||
|
||||
auth.expires_in = data.expires_in;
|
||||
auth.refresh_expires_in = data.refresh_expires_in;
|
||||
auth.access_token = data.access_token;
|
||||
auth.refresh_token = data.refresh_token;
|
||||
auth.id_token = data.id_token;
|
||||
auth.token_type = data.token_type;
|
||||
|
||||
//idp_response_content = structCopy(data); //for debug
|
||||
var token_data = (jwt.decode(data.access_token, arguments.certificate,"RS256"));
|
||||
|
||||
auth.session_state = token_data.session_state;
|
||||
auth.sid = token_data.sid;
|
||||
auth.auth_time = token_data.auth_time;
|
||||
auth.exp = token_data.exp;
|
||||
auth.iat = token_data.iat;
|
||||
|
||||
auth.login = token_data.preferred_username;
|
||||
auth.wz = token_data.ClientID;
|
||||
auth.fullname = token_data.name;
|
||||
auth.groups = token_data.groups;
|
||||
//auth.token_data = structCopy(token_data); //for debug
|
||||
|
||||
return (auth);
|
||||
}
|
||||
|
||||
</cfscript>
|
||||
|
||||
<cffunction name="rethrow" returntype="void">
|
||||
<!--- https://www.raymondcamden.com/2004/03/09/3089633C-9FA0-606B-3F540AE9642A795F --->
|
||||
<cftry>
|
||||
<cfcatch>
|
||||
<cfrethrow/>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
<cfthrow type="Context validation error" message="RETHROW() called outside TRY-CATCH"/>
|
||||
</cffunction>
|
||||
</cfcomponent>
|
||||
@@ -1,6 +0,0 @@
|
||||
корректный период
|
||||
другие WZ
|
||||
? full join
|
||||
детализация - для S3 это бакеты
|
||||
|
||||
|
||||
@@ -1,595 +0,0 @@
|
||||
база rpt сделана из базы billing (название изменено, чтобы избежать путаницы)
|
||||
-- удалены последовательности, переназначены владельцы и права
|
||||
-- удалены внешние ключи
|
||||
|
||||
-- создать роль dbo (владелец), без connect
|
||||
-- создать пользователя nifi, с правом логина
|
||||
-- создать пользователя appserver, с правом логина
|
||||
-- дать права пользователю nifi на схемы и таблицы
|
||||
-- дать права пользователю appserver на схемы и таблицы на чтение
|
||||
|
||||
SET ROLE postgres;
|
||||
|
||||
CREATE SCHEMA IF NOT EXISTS s3billing;
|
||||
CREATE SCHEMA IF NOT EXISTS ngcloud_ru;
|
||||
|
||||
ALTER SCHEMA s3billing OWNER TO dbo;
|
||||
ALTER SCHEMA ngcloud_ru OWNER TO dbo;
|
||||
ALTER DATABASE rpt SET search_path TO s3billing, ngcloud_ru;
|
||||
|
||||
ALTER DEFAULT PRIVILEGES FOR ROLE dbo, postgres GRANT ALL ON TABLES TO nifi;
|
||||
ALTER DEFAULT PRIVILEGES FOR ROLE dbo, postgres GRANT SELECT ON TABLES TO appserver;
|
||||
|
||||
SET ROLE dbo;
|
||||
|
||||
GRANT USAGE ON SCHEMA s3billing TO appserver,nifi;
|
||||
GRANT USAGE ON SCHEMA ngcloud_ru TO appserver,nifi;
|
||||
|
||||
GRANT ALL ON ALL TABLES IN SCHEMA s3billing TO nifi;
|
||||
GRANT SELECT ON ALL TABLES IN SCHEMA s3billing TO appserver;
|
||||
|
||||
GRANT ALL ON ALL TABLES IN SCHEMA ngcloud_ru TO nifi;
|
||||
GRANT SELECT ON ALL TABLES IN SCHEMA ngcloud_ru TO appserver;
|
||||
|
||||
--GRANT ALL ON ALL SEQUENCES IN SCHEMA s3billing TO appserver,nifi;
|
||||
--GRANT ALL ON ALL SEQUENCES IN SCHEMA ngcloud_ru TO appserver,nifi;
|
||||
|
||||
|
||||
--ALTER DEFAULT PRIVILEGES FOR ROLE dbo GRANT ALL ON SEQUENCES TO appserver,nifi;
|
||||
|
||||
--
|
||||
-- PostgreSQL database dump
|
||||
--
|
||||
|
||||
-- Dumped from database version 16.0
|
||||
-- Dumped by pg_dump version 16.4
|
||||
|
||||
-- Started on 2025-09-15 09:50:58
|
||||
|
||||
SET statement_timeout = 0;
|
||||
SET lock_timeout = 0;
|
||||
SET idle_in_transaction_session_timeout = 0;
|
||||
SET client_encoding = 'UTF8';
|
||||
SET standard_conforming_strings = on;
|
||||
SELECT pg_catalog.set_config('search_path', '', false);
|
||||
SET check_function_bodies = false;
|
||||
SET xmloption = content;
|
||||
SET client_min_messages = warning;
|
||||
SET row_security = off;
|
||||
|
||||
SET default_tablespace = '';
|
||||
|
||||
SET default_table_access_method = heap;
|
||||
|
||||
--
|
||||
-- TOC entry 230 (class 1259 OID 2160668)
|
||||
-- Name: bucket_info; Type: TABLE; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS s3billing.bucket_info;
|
||||
CREATE TABLE s3billing.bucket_info (
|
||||
id integer NOT NULL,
|
||||
bucket_id character varying(255) NOT NULL,
|
||||
name character varying(255) NOT NULL,
|
||||
marker character varying(255) NOT NULL,
|
||||
placement_id bigint DEFAULT 0 NOT NULL
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 226 (class 1259 OID 2160642)
|
||||
-- Name: bucket_stat; Type: TABLE; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
DROP TABLE IF EXISTS s3billing.bucket_stat;
|
||||
CREATE TABLE s3billing.bucket_stat (
|
||||
bucket_id bigint,
|
||||
num_shards bigint NOT NULL,
|
||||
tenant character varying(255) DEFAULT NULL::character varying,
|
||||
zone_group bigint NOT NULL,
|
||||
placement_id bigint NOT NULL,
|
||||
explicit_placement_data_pool character varying(255) DEFAULT NULL::character varying,
|
||||
explicit_placement_data_extra_pool character varying(255) DEFAULT NULL::character varying,
|
||||
explicit_placement_index_pool character varying(255) DEFAULT NULL::character varying,
|
||||
index_type_id bigint NOT NULL,
|
||||
versioned boolean DEFAULT false,
|
||||
versioning_enabled boolean DEFAULT false,
|
||||
object_lock_enabled boolean DEFAULT false,
|
||||
mfa_enabled boolean DEFAULT false,
|
||||
owner character varying(255) NOT NULL,
|
||||
bucket_quota_enabled boolean DEFAULT false,
|
||||
bucket_quota_check_on_raw boolean DEFAULT false,
|
||||
bucket_quota_max_size bigint NOT NULL,
|
||||
bucket_quota_max_size_kb bigint NOT NULL,
|
||||
bucket_quota_max_objects bigint NOT NULL,
|
||||
usage_rgw_main_size bigint NOT NULL,
|
||||
usage_rgw_main_size_actual bigint NOT NULL,
|
||||
usage_rgw_main_size_utilized bigint NOT NULL,
|
||||
usage_rgw_main_size_kb bigint NOT NULL,
|
||||
usage_rgw_main_size_kb_actual bigint NOT NULL,
|
||||
usage_rgw_main_size_kb_utilized bigint NOT NULL,
|
||||
usage_rgw_main_num_objects bigint NOT NULL,
|
||||
usage_rgw_multimeta_size bigint,
|
||||
usage_rgw_multimeta_size_actual bigint,
|
||||
usage_rgw_multimeta_size_utilized bigint,
|
||||
usage_rgw_multimeta_size_kb bigint,
|
||||
usage_rgw_multimeta_size_kb_actual bigint,
|
||||
usage_rgw_multimeta_size_kb_utilized bigint,
|
||||
usage_rgw_multimeta_num_objects bigint,
|
||||
creation_time timestamp without time zone NOT NULL,
|
||||
mtime timestamp without time zone NOT NULL,
|
||||
timestamp_addition timestamp without time zone DEFAULT date_trunc('hour'::text, CURRENT_TIMESTAMP)
|
||||
);
|
||||
|
||||
--
|
||||
-- TOC entry 245 (class 1259 OID 2160763)
|
||||
-- Name: category; Type: TABLE; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
DROP TABLE IF EXISTS s3billing.category;
|
||||
CREATE TABLE s3billing.category (
|
||||
id integer NOT NULL,
|
||||
name character varying(255) NOT NULL
|
||||
);
|
||||
|
||||
--
|
||||
-- TOC entry 225 (class 1259 OID 2160635)
|
||||
-- Name: goose_db_version; Type: TABLE; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
DROP TABLE IF EXISTS s3billing.goose_db_version;
|
||||
CREATE TABLE s3billing.goose_db_version (
|
||||
id integer NOT NULL,
|
||||
version_id bigint NOT NULL,
|
||||
is_applied boolean NOT NULL,
|
||||
tstamp timestamp without time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 234 (class 1259 OID 2160684)
|
||||
-- Name: index_type; Type: TABLE; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
DROP TABLE IF EXISTS index_type;
|
||||
CREATE TABLE s3billing.index_type (
|
||||
id integer NOT NULL,
|
||||
name character varying(255) NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 232 (class 1259 OID 2160677)
|
||||
-- Name: placement; Type: TABLE; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
DROP TABLE IF EXISTS s3billing.placement;
|
||||
CREATE TABLE s3billing.placement (
|
||||
id integer NOT NULL,
|
||||
name character varying(255) NOT NULL
|
||||
);
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 239 (class 1259 OID 2160705)
|
||||
-- Name: usage_bucket_by_user; Type: TABLE; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
DROP TABLE IF EXISTS s3billing.usage_bucket_by_user;
|
||||
CREATE TABLE s3billing.usage_bucket_by_user (
|
||||
bucketid bigint,
|
||||
"time" timestamp without time zone NOT NULL,
|
||||
bytes_sent bigint NOT NULL,
|
||||
bytes_received bigint NOT NULL,
|
||||
ops bigint NOT NULL,
|
||||
successful_ops bigint NOT NULL,
|
||||
date_start timestamp without time zone NOT NULL,
|
||||
date_end timestamp without time zone NOT NULL,
|
||||
user_id bigint NOT NULL,
|
||||
category_id bigint NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 238 (class 1259 OID 2160698)
|
||||
-- Name: usage_stat_summary; Type: TABLE; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
DROP TABLE IF EXISTS s3billing.usage_stat_summary;
|
||||
CREATE TABLE s3billing.usage_stat_summary (
|
||||
id integer NOT NULL,
|
||||
userid character varying(255) NOT NULL,
|
||||
category character varying(255) NOT NULL,
|
||||
bytes_sent bigint NOT NULL,
|
||||
bytes_received bigint NOT NULL,
|
||||
ops bigint NOT NULL,
|
||||
successful_ops bigint NOT NULL,
|
||||
date_start timestamp without time zone NOT NULL,
|
||||
date_end timestamp without time zone NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 236 (class 1259 OID 2160691)
|
||||
-- Name: usage_stat_total; Type: TABLE; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
DROP TABLE IF EXISTS s3billing.usage_stat_total;
|
||||
CREATE TABLE s3billing.usage_stat_total (
|
||||
id integer NOT NULL,
|
||||
userid character varying(255) NOT NULL,
|
||||
bytes_sent bigint NOT NULL,
|
||||
bytes_received bigint NOT NULL,
|
||||
ops bigint NOT NULL,
|
||||
successful_ops bigint NOT NULL,
|
||||
date_start timestamp without time zone NOT NULL,
|
||||
date_end timestamp without time zone NOT NULL
|
||||
);
|
||||
|
||||
--
|
||||
-- TOC entry 243 (class 1259 OID 2160751)
|
||||
-- Name: user_info; Type: TABLE; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
DROP TABLE IF EXISTS s3billing.user_info;
|
||||
CREATE TABLE s3billing.user_info (
|
||||
id integer NOT NULL,
|
||||
name character varying(255) NOT NULL,
|
||||
owner character varying(255) NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 241 (class 1259 OID 2160712)
|
||||
-- Name: user_quota_bucket; Type: TABLE; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
DROP TABLE IF EXISTS s3billing.user_quota_bucket;
|
||||
CREATE TABLE s3billing.user_quota_bucket (
|
||||
id integer NOT NULL,
|
||||
userid character varying(255) NOT NULL,
|
||||
enabled boolean DEFAULT false,
|
||||
check_on_raw boolean DEFAULT false,
|
||||
max_size bigint NOT NULL,
|
||||
max_size_kb bigint NOT NULL,
|
||||
max_objects bigint NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 228 (class 1259 OID 2160661)
|
||||
-- Name: zone_group; Type: TABLE; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
DROP TABLE IF EXISTS s3billing.zone_group;
|
||||
CREATE TABLE s3billing.zone_group (
|
||||
id integer NOT NULL,
|
||||
name uuid NOT NULL
|
||||
);
|
||||
|
||||
--
|
||||
-- TOC entry 3278 (class 2606 OID 2160675)
|
||||
-- Name: bucket_info bucket_info_pkey; Type: CONSTRAINT; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY s3billing.bucket_info
|
||||
ADD CONSTRAINT bucket_info_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3273 (class 2606 OID 2476484)
|
||||
-- Name: bucket_stat bucket_stat_unique; Type: CONSTRAINT; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
--ALTER TABLE ONLY s3billing.bucket_stat
|
||||
-- ADD CONSTRAINT bucket_stat_unique UNIQUE (bucket_id, placement_id, timestamp_addition);
|
||||
|
||||
ALTER TABLE ONLY s3billing.bucket_stat
|
||||
ADD CONSTRAINT bucket_stat_pkey PRIMARY KEY (bucket_id, placement_id, timestamp_addition);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3298 (class 2606 OID 2160768)
|
||||
-- Name: category category_pkey; Type: CONSTRAINT; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY s3billing.category
|
||||
ADD CONSTRAINT category_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3270 (class 2606 OID 2160640)
|
||||
-- Name: goose_db_version goose_db_version_pkey; Type: CONSTRAINT; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY s3billing.goose_db_version
|
||||
ADD CONSTRAINT goose_db_version_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3284 (class 2606 OID 2160689)
|
||||
-- Name: index_type index_type_pkey; Type: CONSTRAINT; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY s3billing.index_type
|
||||
ADD CONSTRAINT index_type_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3282 (class 2606 OID 2160682)
|
||||
-- Name: placement placement_pkey; Type: CONSTRAINT; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY s3billing.placement
|
||||
ADD CONSTRAINT placement_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3290 (class 2606 OID 2476705)
|
||||
-- Name: usage_bucket_by_user usage_bucket_by_user_unique; Type: CONSTRAINT; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
--ALTER TABLE ONLY s3billing.usage_bucket_by_user
|
||||
-- ADD CONSTRAINT usage_bucket_by_user_unique UNIQUE (bucketid, date_start, date_end, user_id, category_id);
|
||||
ALTER TABLE ONLY s3billing.usage_bucket_by_user
|
||||
ADD CONSTRAINT usage_bucket_by_user_pkey PRIMARY KEY (bucketid, date_start, date_end, user_id, category_id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3288 (class 2606 OID 2160703)
|
||||
-- Name: usage_stat_summary usage_stat_summary_pkey; Type: CONSTRAINT; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY s3billing.usage_stat_summary
|
||||
ADD CONSTRAINT usage_stat_summary_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3286 (class 2606 OID 2160696)
|
||||
-- Name: usage_stat_total usage_stat_total_pkey; Type: CONSTRAINT; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY s3billing.usage_stat_total
|
||||
ADD CONSTRAINT usage_stat_total_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3295 (class 2606 OID 2160758)
|
||||
-- Name: user_info user_info_pkey; Type: CONSTRAINT; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY s3billing.user_info
|
||||
ADD CONSTRAINT user_info_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3292 (class 2606 OID 2160719)
|
||||
-- Name: user_quota_bucket user_quota_bucket_pkey; Type: CONSTRAINT; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY s3billing.user_quota_bucket
|
||||
ADD CONSTRAINT user_quota_bucket_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3275 (class 2606 OID 2160666)
|
||||
-- Name: zone_group zone_group_pkey; Type: CONSTRAINT; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY s3billing.zone_group
|
||||
ADD CONSTRAINT zone_group_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3276 (class 1259 OID 2474077)
|
||||
-- Name: bucket_info_name_idx; Type: INDEX; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
CREATE INDEX bucket_info_name_idx ON s3billing.bucket_info USING btree (name);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3279 (class 1259 OID 2474078)
|
||||
-- Name: bucket_info_placement_id_idx; Type: INDEX; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
CREATE INDEX bucket_info_placement_id_idx ON s3billing.bucket_info USING btree (placement_id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3271 (class 1259 OID 2474094)
|
||||
-- Name: bucket_stat_owner_idx; Type: INDEX; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
CREATE INDEX bucket_stat_owner_idx ON s3billing.bucket_stat USING btree (owner);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3296 (class 1259 OID 2474445)
|
||||
-- Name: category_name_idx; Type: INDEX; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
CREATE UNIQUE INDEX category_name_idx ON s3billing.category USING btree (name);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3280 (class 1259 OID 2474468)
|
||||
-- Name: placement_name_idx; Type: INDEX; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
CREATE UNIQUE INDEX placement_name_idx ON s3billing.placement USING btree (name);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3293 (class 1259 OID 2474438)
|
||||
-- Name: user_info_name_idx; Type: INDEX; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
CREATE INDEX user_info_name_idx ON s3billing.user_info USING btree (name);
|
||||
|
||||
|
||||
|
||||
-- Completed on 2025-09-15 09:50:59
|
||||
|
||||
--
|
||||
-- PostgreSQL database dump complete
|
||||
--
|
||||
|
||||
-------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------
|
||||
|
||||
DROP TABLE IF EXISTS ngcloud_ru.capacity_resource;
|
||||
CREATE TABLE ngcloud_ru.capacity_resource (
|
||||
vdc_id uuid NOT NULL,
|
||||
"timestamp" timestamp with time zone NOT NULL,
|
||||
cpu_allocated integer NOT NULL,
|
||||
cpu_limit integer NOT NULL,
|
||||
cpu_reserved integer NOT NULL,
|
||||
cpu_used integer NOT NULL,
|
||||
cpu_speed integer NOT NULL,
|
||||
mem_allocated integer NOT NULL,
|
||||
mem_limit integer NOT NULL,
|
||||
mem_reserved integer NOT NULL,
|
||||
mem_used integer NOT NULL
|
||||
);
|
||||
|
||||
--
|
||||
-- TOC entry 223 (class 1259 OID 1893993)
|
||||
-- Name: capacity_storage; Type: TABLE; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
DROP TABLE IF EXISTS ngcloud_ru.capacity_storage;
|
||||
CREATE TABLE ngcloud_ru.capacity_storage (
|
||||
vdc_id uuid NOT NULL,
|
||||
storage_profile_types_id integer NOT NULL,
|
||||
"timestamp" timestamp with time zone NOT NULL,
|
||||
id uuid NOT NULL,
|
||||
"limit" integer NOT NULL,
|
||||
used integer NOT NULL
|
||||
);
|
||||
|
||||
--
|
||||
-- TOC entry 220 (class 1259 OID 1893965)
|
||||
-- Name: storage_profile_types; Type: TABLE; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
DROP TABLE IF EXISTS ngcloud_ru.storage_profile_types;
|
||||
CREATE TABLE ngcloud_ru.storage_profile_types (
|
||||
id integer NOT NULL,
|
||||
name character varying(255) NOT NULL
|
||||
);
|
||||
|
||||
--
|
||||
-- TOC entry 218 (class 1259 OID 1893959)
|
||||
-- Name: tenant; Type: TABLE; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
DROP TABLE IF EXISTS ngcloud_ru.tenant;
|
||||
CREATE TABLE ngcloud_ru.tenant (
|
||||
id uuid NOT NULL,
|
||||
name character varying(255) NOT NULL,
|
||||
wzcode bigint
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 221 (class 1259 OID 1893973)
|
||||
-- Name: vdc; Type: TABLE; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
DROP TABLE IF EXISTS ngcloud_ru.vdc;
|
||||
CREATE TABLE ngcloud_ru.vdc (
|
||||
id uuid NOT NULL,
|
||||
tenant_id uuid NOT NULL,
|
||||
name character varying(255) NOT NULL
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3255 (class 2606 OID 1893987)
|
||||
-- Name: capacity_resource capacity_resource_pkey; Type: CONSTRAINT; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY ngcloud_ru.capacity_resource
|
||||
ADD CONSTRAINT capacity_resource_pkey PRIMARY KEY (vdc_id, "timestamp");
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3257 (class 2606 OID 1893997)
|
||||
-- Name: capacity_storage capacity_storage_pkey; Type: CONSTRAINT; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY ngcloud_ru.capacity_storage
|
||||
ADD CONSTRAINT capacity_storage_pkey PRIMARY KEY (vdc_id, id, "timestamp");
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3249 (class 2606 OID 1893972)
|
||||
-- Name: storage_profile_types storage_profile_types_name_key; Type: CONSTRAINT; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY ngcloud_ru.storage_profile_types
|
||||
ADD CONSTRAINT storage_profile_types_name_key UNIQUE (name);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3251 (class 2606 OID 1893970)
|
||||
-- Name: storage_profile_types storage_profile_types_pkey; Type: CONSTRAINT; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY ngcloud_ru.storage_profile_types
|
||||
ADD CONSTRAINT storage_profile_types_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3247 (class 2606 OID 1893963)
|
||||
-- Name: tenant tenant_pkey; Type: CONSTRAINT; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY ngcloud_ru.tenant
|
||||
ADD CONSTRAINT tenant_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3253 (class 2606 OID 1893977)
|
||||
-- Name: vdc vdc_pkey; Type: CONSTRAINT; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY ngcloud_ru.vdc
|
||||
ADD CONSTRAINT vdc_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3259 (class 2606 OID 1893988)
|
||||
-- Name: capacity_resource capacity_resource_vdc_id_fkey; Type: FK CONSTRAINT; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
|
||||
--ALTER TABLE ONLY ngcloud_ru.capacity_resource
|
||||
-- ADD CONSTRAINT capacity_resource_vdc_id_fkey FOREIGN KEY (vdc_id) REFERENCES ngcloud_ru.vdc(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3260 (class 2606 OID 1894003)
|
||||
-- Name: capacity_storage capacity_storage_storage_profile_types_id_fkey; Type: FK CONSTRAINT; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
|
||||
--ALTER TABLE ONLY ngcloud_ru.capacity_storage
|
||||
-- ADD CONSTRAINT capacity_storage_storage_profile_types_id_fkey FOREIGN KEY (storage_profile_types_id) REFERENCES ngcloud_ru.storage_profile_types(id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3261 (class 2606 OID 1893998)
|
||||
-- Name: capacity_storage capacity_storage_vdc_id_fkey; Type: FK CONSTRAINT; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
|
||||
--ALTER TABLE ONLY ngcloud_ru.capacity_storage
|
||||
-- ADD CONSTRAINT capacity_storage_vdc_id_fkey FOREIGN KEY (vdc_id) REFERENCES ngcloud_ru.vdc(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3258 (class 2606 OID 1893978)
|
||||
-- Name: vdc vdc_tenant_id_fkey; Type: FK CONSTRAINT; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
|
||||
--ALTER TABLE ONLY ngcloud_ru.vdc
|
||||
-- ADD CONSTRAINT vdc_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES ngcloud_ru.tenant(id);
|
||||
|
||||
|
||||
-- Completed on 2025-09-15 09:53:18
|
||||
|
||||
--
|
||||
-- PostgreSQL database dump complete
|
||||
--
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
set role postgres;
|
||||
--
|
||||
CREATE SCHEMA IF NOT EXISTS gpu;
|
||||
--ALTER SCHEMA gpu OWNER TO dbo;
|
||||
GRANT USAGE ON SCHEMA gpu TO nifi;
|
||||
|
||||
GRANT ALL ON ALL TABLES IN SCHEMA gpu TO nifi;
|
||||
GRANT ALL ON ALL SEQUENCES IN SCHEMA gpu TO nifi;
|
||||
|
||||
--ALTER DEFAULT PRIVILEGES IN SCHEMA gpu GRANT ALL ON TABLES TO nifi;
|
||||
--ALTER DEFAULT PRIVILEGES IN SCHEMA gpu GRANT ALL ON SEQUENCES TO nifi;
|
||||
|
||||
ALTER DEFAULT PRIVILEGES FOR ROLE dbo, postgres IN SCHEMA gpu GRANT ALL ON TABLES TO nifi;
|
||||
ALTER DEFAULT PRIVILEGES FOR ROLE dbo, postgres IN SCHEMA gpu GRANT ALL ON SEQUENCES TO nifi;
|
||||
|
||||
--SET ROLE dbo;
|
||||
|
||||
DROP TABLE IF EXISTS gpu.vm;
|
||||
CREATE TABLE gpu.vm (
|
||||
objUUID uuid NOT NULL PRIMARY KEY
|
||||
,groupUUID uuid NULL
|
||||
,objId varchar(255) NULL
|
||||
,ClientID varchar(255) NULL -- WZ
|
||||
,VCD varchar(255) NULL
|
||||
,Org varchar(255) NULL
|
||||
,OrgVDC varchar(255) NULL
|
||||
,vCenter varchar(255) NULL
|
||||
,GPU varchar(255) NULL
|
||||
,dt_load timestamptz NOT NULL
|
||||
);
|
||||
ALTER TABLE gpu.vm OWNER TO dbo;
|
||||
/*
|
||||
{
|
||||
"type": "record",
|
||||
"name": "gpu.vm",
|
||||
"namespace": "org.apache.nifi",
|
||||
"fields": [
|
||||
{"name":"objUUID", "type":{"type": "string", "logicalType": "uuid"}},
|
||||
{"name":"groupUUID", "type":[{"type": "string", "logicalType": "uuid"} ,"null"]},
|
||||
{"name":"objId", "type":["string" ,"null"]},
|
||||
{"name":"ClientID", "type":["int" ,"null"]},
|
||||
{"name":"VCD", "type":["string" ,"null"]},
|
||||
{"name":"Org", "type":["string" ,"null"]},
|
||||
{"name":"OrgVDC", "type":["string" ,"null"]},
|
||||
{"name":"vCenter", "type":["string" ,"null"]},
|
||||
{"name":"GPU", "type":["string" ,"null"]},
|
||||
{"name":"VCD", "type":["string" ,"null"]},
|
||||
{"name":"dt_load","type":{"type": "long", "logicalType": "local-timestamp-millis"}}
|
||||
]
|
||||
}
|
||||
*/
|
||||
|
||||
DROP TABLE IF EXISTS gpu.vm_power_state;
|
||||
CREATE TABLE gpu.vm_power_state (
|
||||
objId varchar(255) NULL
|
||||
,ts timestamptz NOT NULL -- без таймштампа загрузки
|
||||
,value int NULL
|
||||
,CONSTRAINT PK_vm_power_state PRIMARY KEY(objId, ts)
|
||||
);
|
||||
ALTER TABLE gpu.vm_power_state OWNER TO dbo;
|
||||
/*
|
||||
{
|
||||
"type": "record",
|
||||
"name": "gpu.vm_power_state,
|
||||
"namespace": "org.apache.nifi",
|
||||
"fields": [
|
||||
{"name":"objId", "type":["string" ,"null"]},
|
||||
{"name":"ts","type":{"type": "long", "logicalType": "local-timestamp-millis"}},
|
||||
{"name":"value", "type":["int" ,"null"]}
|
||||
]
|
||||
}
|
||||
*/
|
||||
@@ -1,828 +0,0 @@
|
||||
--
|
||||
-- PostgreSQL database dump
|
||||
--
|
||||
|
||||
-- Dumped from database version 16.0
|
||||
-- Dumped by pg_dump version 16.4
|
||||
|
||||
-- Started on 2025-09-15 09:50:58
|
||||
|
||||
SET statement_timeout = 0;
|
||||
SET lock_timeout = 0;
|
||||
SET idle_in_transaction_session_timeout = 0;
|
||||
SET client_encoding = 'UTF8';
|
||||
SET standard_conforming_strings = on;
|
||||
SELECT pg_catalog.set_config('search_path', '', false);
|
||||
SET check_function_bodies = false;
|
||||
SET xmloption = content;
|
||||
SET client_min_messages = warning;
|
||||
SET row_security = off;
|
||||
|
||||
SET default_tablespace = '';
|
||||
|
||||
SET default_table_access_method = heap;
|
||||
|
||||
--
|
||||
-- TOC entry 230 (class 1259 OID 2160668)
|
||||
-- Name: bucket_info; Type: TABLE; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
CREATE TABLE s3billing.bucket_info (
|
||||
id integer NOT NULL,
|
||||
bucket_id character varying(255) NOT NULL,
|
||||
name character varying(255) NOT NULL,
|
||||
marker character varying(255) NOT NULL,
|
||||
placement_id bigint DEFAULT 0 NOT NULL
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE s3billing.bucket_info OWNER TO s3billing;
|
||||
|
||||
--
|
||||
-- TOC entry 229 (class 1259 OID 2160667)
|
||||
-- Name: bucket_info_id_seq; Type: SEQUENCE; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
CREATE SEQUENCE s3billing.bucket_info_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
ALTER SEQUENCE s3billing.bucket_info_id_seq OWNER TO s3billing;
|
||||
|
||||
--
|
||||
-- TOC entry 3448 (class 0 OID 0)
|
||||
-- Dependencies: 229
|
||||
-- Name: bucket_info_id_seq; Type: SEQUENCE OWNED BY; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER SEQUENCE s3billing.bucket_info_id_seq OWNED BY s3billing.bucket_info.id;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 226 (class 1259 OID 2160642)
|
||||
-- Name: bucket_stat; Type: TABLE; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
CREATE TABLE s3billing.bucket_stat (
|
||||
bucket_id bigint,
|
||||
num_shards bigint NOT NULL,
|
||||
tenant character varying(255) DEFAULT NULL::character varying,
|
||||
zone_group bigint NOT NULL,
|
||||
placement_id bigint NOT NULL,
|
||||
explicit_placement_data_pool character varying(255) DEFAULT NULL::character varying,
|
||||
explicit_placement_data_extra_pool character varying(255) DEFAULT NULL::character varying,
|
||||
explicit_placement_index_pool character varying(255) DEFAULT NULL::character varying,
|
||||
index_type_id bigint NOT NULL,
|
||||
versioned boolean DEFAULT false,
|
||||
versioning_enabled boolean DEFAULT false,
|
||||
object_lock_enabled boolean DEFAULT false,
|
||||
mfa_enabled boolean DEFAULT false,
|
||||
owner character varying(255) NOT NULL,
|
||||
bucket_quota_enabled boolean DEFAULT false,
|
||||
bucket_quota_check_on_raw boolean DEFAULT false,
|
||||
bucket_quota_max_size bigint NOT NULL,
|
||||
bucket_quota_max_size_kb bigint NOT NULL,
|
||||
bucket_quota_max_objects bigint NOT NULL,
|
||||
usage_rgw_main_size bigint NOT NULL,
|
||||
usage_rgw_main_size_actual bigint NOT NULL,
|
||||
usage_rgw_main_size_utilized bigint NOT NULL,
|
||||
usage_rgw_main_size_kb bigint NOT NULL,
|
||||
usage_rgw_main_size_kb_actual bigint NOT NULL,
|
||||
usage_rgw_main_size_kb_utilized bigint NOT NULL,
|
||||
usage_rgw_main_num_objects bigint NOT NULL,
|
||||
usage_rgw_multimeta_size bigint,
|
||||
usage_rgw_multimeta_size_actual bigint,
|
||||
usage_rgw_multimeta_size_utilized bigint,
|
||||
usage_rgw_multimeta_size_kb bigint,
|
||||
usage_rgw_multimeta_size_kb_actual bigint,
|
||||
usage_rgw_multimeta_size_kb_utilized bigint,
|
||||
usage_rgw_multimeta_num_objects bigint,
|
||||
creation_time timestamp without time zone NOT NULL,
|
||||
mtime timestamp without time zone NOT NULL,
|
||||
timestamp_addition timestamp without time zone DEFAULT date_trunc('hour'::text, CURRENT_TIMESTAMP)
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE s3billing.bucket_stat OWNER TO s3billing;
|
||||
|
||||
--
|
||||
-- TOC entry 245 (class 1259 OID 2160763)
|
||||
-- Name: category; Type: TABLE; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
CREATE TABLE s3billing.category (
|
||||
id integer NOT NULL,
|
||||
name character varying(255) NOT NULL
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE s3billing.category OWNER TO s3billing;
|
||||
|
||||
--
|
||||
-- TOC entry 244 (class 1259 OID 2160762)
|
||||
-- Name: category_id_seq; Type: SEQUENCE; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
CREATE SEQUENCE s3billing.category_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
ALTER SEQUENCE s3billing.category_id_seq OWNER TO s3billing;
|
||||
|
||||
--
|
||||
-- TOC entry 3451 (class 0 OID 0)
|
||||
-- Dependencies: 244
|
||||
-- Name: category_id_seq; Type: SEQUENCE OWNED BY; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER SEQUENCE s3billing.category_id_seq OWNED BY s3billing.category.id;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 225 (class 1259 OID 2160635)
|
||||
-- Name: goose_db_version; Type: TABLE; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
CREATE TABLE s3billing.goose_db_version (
|
||||
id integer NOT NULL,
|
||||
version_id bigint NOT NULL,
|
||||
is_applied boolean NOT NULL,
|
||||
tstamp timestamp without time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE s3billing.goose_db_version OWNER TO s3billing;
|
||||
|
||||
--
|
||||
-- TOC entry 224 (class 1259 OID 2160634)
|
||||
-- Name: goose_db_version_id_seq; Type: SEQUENCE; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER TABLE s3billing.goose_db_version ALTER COLUMN id ADD GENERATED BY DEFAULT AS IDENTITY (
|
||||
SEQUENCE NAME s3billing.goose_db_version_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 234 (class 1259 OID 2160684)
|
||||
-- Name: index_type; Type: TABLE; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
CREATE TABLE s3billing.index_type (
|
||||
id integer NOT NULL,
|
||||
name character varying(255) NOT NULL
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE s3billing.index_type OWNER TO s3billing;
|
||||
|
||||
--
|
||||
-- TOC entry 233 (class 1259 OID 2160683)
|
||||
-- Name: index_type_id_seq; Type: SEQUENCE; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
CREATE SEQUENCE s3billing.index_type_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
ALTER SEQUENCE s3billing.index_type_id_seq OWNER TO s3billing;
|
||||
|
||||
--
|
||||
-- TOC entry 3454 (class 0 OID 0)
|
||||
-- Dependencies: 233
|
||||
-- Name: index_type_id_seq; Type: SEQUENCE OWNED BY; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER SEQUENCE s3billing.index_type_id_seq OWNED BY s3billing.index_type.id;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 232 (class 1259 OID 2160677)
|
||||
-- Name: placement; Type: TABLE; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
CREATE TABLE s3billing.placement (
|
||||
id integer NOT NULL,
|
||||
name character varying(255) NOT NULL
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE s3billing.placement OWNER TO s3billing;
|
||||
|
||||
--
|
||||
-- TOC entry 231 (class 1259 OID 2160676)
|
||||
-- Name: placement_id_seq; Type: SEQUENCE; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
CREATE SEQUENCE s3billing.placement_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
ALTER SEQUENCE s3billing.placement_id_seq OWNER TO s3billing;
|
||||
|
||||
--
|
||||
-- TOC entry 3456 (class 0 OID 0)
|
||||
-- Dependencies: 231
|
||||
-- Name: placement_id_seq; Type: SEQUENCE OWNED BY; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER SEQUENCE s3billing.placement_id_seq OWNED BY s3billing.placement.id;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 239 (class 1259 OID 2160705)
|
||||
-- Name: usage_bucket_by_user; Type: TABLE; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
CREATE TABLE s3billing.usage_bucket_by_user (
|
||||
bucketid bigint,
|
||||
"time" timestamp without time zone NOT NULL,
|
||||
bytes_sent bigint NOT NULL,
|
||||
bytes_received bigint NOT NULL,
|
||||
ops bigint NOT NULL,
|
||||
successful_ops bigint NOT NULL,
|
||||
date_start timestamp without time zone NOT NULL,
|
||||
date_end timestamp without time zone NOT NULL,
|
||||
user_id bigint NOT NULL,
|
||||
category_id bigint NOT NULL
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE s3billing.usage_bucket_by_user OWNER TO s3billing;
|
||||
|
||||
--
|
||||
-- TOC entry 238 (class 1259 OID 2160698)
|
||||
-- Name: usage_stat_summary; Type: TABLE; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
CREATE TABLE s3billing.usage_stat_summary (
|
||||
id integer NOT NULL,
|
||||
userid character varying(255) NOT NULL,
|
||||
category character varying(255) NOT NULL,
|
||||
bytes_sent bigint NOT NULL,
|
||||
bytes_received bigint NOT NULL,
|
||||
ops bigint NOT NULL,
|
||||
successful_ops bigint NOT NULL,
|
||||
date_start timestamp without time zone NOT NULL,
|
||||
date_end timestamp without time zone NOT NULL
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE s3billing.usage_stat_summary OWNER TO s3billing;
|
||||
|
||||
--
|
||||
-- TOC entry 237 (class 1259 OID 2160697)
|
||||
-- Name: usage_stat_summary_id_seq; Type: SEQUENCE; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
CREATE SEQUENCE s3billing.usage_stat_summary_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
ALTER SEQUENCE s3billing.usage_stat_summary_id_seq OWNER TO s3billing;
|
||||
|
||||
--
|
||||
-- TOC entry 3459 (class 0 OID 0)
|
||||
-- Dependencies: 237
|
||||
-- Name: usage_stat_summary_id_seq; Type: SEQUENCE OWNED BY; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER SEQUENCE s3billing.usage_stat_summary_id_seq OWNED BY s3billing.usage_stat_summary.id;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 236 (class 1259 OID 2160691)
|
||||
-- Name: usage_stat_total; Type: TABLE; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
CREATE TABLE s3billing.usage_stat_total (
|
||||
id integer NOT NULL,
|
||||
userid character varying(255) NOT NULL,
|
||||
bytes_sent bigint NOT NULL,
|
||||
bytes_received bigint NOT NULL,
|
||||
ops bigint NOT NULL,
|
||||
successful_ops bigint NOT NULL,
|
||||
date_start timestamp without time zone NOT NULL,
|
||||
date_end timestamp without time zone NOT NULL
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE s3billing.usage_stat_total OWNER TO s3billing;
|
||||
|
||||
--
|
||||
-- TOC entry 235 (class 1259 OID 2160690)
|
||||
-- Name: usage_stat_total_id_seq; Type: SEQUENCE; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
CREATE SEQUENCE s3billing.usage_stat_total_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
ALTER SEQUENCE s3billing.usage_stat_total_id_seq OWNER TO s3billing;
|
||||
|
||||
--
|
||||
-- TOC entry 3461 (class 0 OID 0)
|
||||
-- Dependencies: 235
|
||||
-- Name: usage_stat_total_id_seq; Type: SEQUENCE OWNED BY; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER SEQUENCE s3billing.usage_stat_total_id_seq OWNED BY s3billing.usage_stat_total.id;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 243 (class 1259 OID 2160751)
|
||||
-- Name: user_info; Type: TABLE; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
CREATE TABLE s3billing.user_info (
|
||||
id integer NOT NULL,
|
||||
name character varying(255) NOT NULL,
|
||||
owner character varying(255) NOT NULL
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE s3billing.user_info OWNER TO s3billing;
|
||||
|
||||
--
|
||||
-- TOC entry 242 (class 1259 OID 2160750)
|
||||
-- Name: user_info_id_seq; Type: SEQUENCE; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
CREATE SEQUENCE s3billing.user_info_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
ALTER SEQUENCE s3billing.user_info_id_seq OWNER TO s3billing;
|
||||
|
||||
--
|
||||
-- TOC entry 3463 (class 0 OID 0)
|
||||
-- Dependencies: 242
|
||||
-- Name: user_info_id_seq; Type: SEQUENCE OWNED BY; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER SEQUENCE s3billing.user_info_id_seq OWNED BY s3billing.user_info.id;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 241 (class 1259 OID 2160712)
|
||||
-- Name: user_quota_bucket; Type: TABLE; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
CREATE TABLE s3billing.user_quota_bucket (
|
||||
id integer NOT NULL,
|
||||
userid character varying(255) NOT NULL,
|
||||
enabled boolean DEFAULT false,
|
||||
check_on_raw boolean DEFAULT false,
|
||||
max_size bigint NOT NULL,
|
||||
max_size_kb bigint NOT NULL,
|
||||
max_objects bigint NOT NULL
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE s3billing.user_quota_bucket OWNER TO s3billing;
|
||||
|
||||
--
|
||||
-- TOC entry 240 (class 1259 OID 2160711)
|
||||
-- Name: user_quota_bucket_id_seq; Type: SEQUENCE; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
CREATE SEQUENCE s3billing.user_quota_bucket_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
ALTER SEQUENCE s3billing.user_quota_bucket_id_seq OWNER TO s3billing;
|
||||
|
||||
--
|
||||
-- TOC entry 3465 (class 0 OID 0)
|
||||
-- Dependencies: 240
|
||||
-- Name: user_quota_bucket_id_seq; Type: SEQUENCE OWNED BY; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER SEQUENCE s3billing.user_quota_bucket_id_seq OWNED BY s3billing.user_quota_bucket.id;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 228 (class 1259 OID 2160661)
|
||||
-- Name: zone_group; Type: TABLE; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
CREATE TABLE s3billing.zone_group (
|
||||
id integer NOT NULL,
|
||||
name uuid NOT NULL
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE s3billing.zone_group OWNER TO s3billing;
|
||||
|
||||
--
|
||||
-- TOC entry 227 (class 1259 OID 2160660)
|
||||
-- Name: zone_group_id_seq; Type: SEQUENCE; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
CREATE SEQUENCE s3billing.zone_group_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
ALTER SEQUENCE s3billing.zone_group_id_seq OWNER TO s3billing;
|
||||
|
||||
--
|
||||
-- TOC entry 3467 (class 0 OID 0)
|
||||
-- Dependencies: 227
|
||||
-- Name: zone_group_id_seq; Type: SEQUENCE OWNED BY; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER SEQUENCE s3billing.zone_group_id_seq OWNED BY s3billing.zone_group.id;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3258 (class 2604 OID 2160671)
|
||||
-- Name: bucket_info id; Type: DEFAULT; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY s3billing.bucket_info ALTER COLUMN id SET DEFAULT nextval('s3billing.bucket_info_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3268 (class 2604 OID 2160766)
|
||||
-- Name: category id; Type: DEFAULT; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY s3billing.category ALTER COLUMN id SET DEFAULT nextval('s3billing.category_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3261 (class 2604 OID 2160687)
|
||||
-- Name: index_type id; Type: DEFAULT; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY s3billing.index_type ALTER COLUMN id SET DEFAULT nextval('s3billing.index_type_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3260 (class 2604 OID 2160680)
|
||||
-- Name: placement id; Type: DEFAULT; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY s3billing.placement ALTER COLUMN id SET DEFAULT nextval('s3billing.placement_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3263 (class 2604 OID 2160701)
|
||||
-- Name: usage_stat_summary id; Type: DEFAULT; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY s3billing.usage_stat_summary ALTER COLUMN id SET DEFAULT nextval('s3billing.usage_stat_summary_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3262 (class 2604 OID 2160694)
|
||||
-- Name: usage_stat_total id; Type: DEFAULT; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY s3billing.usage_stat_total ALTER COLUMN id SET DEFAULT nextval('s3billing.usage_stat_total_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3267 (class 2604 OID 2160754)
|
||||
-- Name: user_info id; Type: DEFAULT; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY s3billing.user_info ALTER COLUMN id SET DEFAULT nextval('s3billing.user_info_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3264 (class 2604 OID 2160715)
|
||||
-- Name: user_quota_bucket id; Type: DEFAULT; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY s3billing.user_quota_bucket ALTER COLUMN id SET DEFAULT nextval('s3billing.user_quota_bucket_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3257 (class 2604 OID 2160664)
|
||||
-- Name: zone_group id; Type: DEFAULT; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY s3billing.zone_group ALTER COLUMN id SET DEFAULT nextval('s3billing.zone_group_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3278 (class 2606 OID 2160675)
|
||||
-- Name: bucket_info bucket_info_pkey; Type: CONSTRAINT; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY s3billing.bucket_info
|
||||
ADD CONSTRAINT bucket_info_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3273 (class 2606 OID 2476484)
|
||||
-- Name: bucket_stat bucket_stat_unique; Type: CONSTRAINT; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY s3billing.bucket_stat
|
||||
ADD CONSTRAINT bucket_stat_unique UNIQUE (bucket_id, placement_id, timestamp_addition);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3298 (class 2606 OID 2160768)
|
||||
-- Name: category category_pkey; Type: CONSTRAINT; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY s3billing.category
|
||||
ADD CONSTRAINT category_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3270 (class 2606 OID 2160640)
|
||||
-- Name: goose_db_version goose_db_version_pkey; Type: CONSTRAINT; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY s3billing.goose_db_version
|
||||
ADD CONSTRAINT goose_db_version_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3284 (class 2606 OID 2160689)
|
||||
-- Name: index_type index_type_pkey; Type: CONSTRAINT; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY s3billing.index_type
|
||||
ADD CONSTRAINT index_type_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3282 (class 2606 OID 2160682)
|
||||
-- Name: placement placement_pkey; Type: CONSTRAINT; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY s3billing.placement
|
||||
ADD CONSTRAINT placement_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3290 (class 2606 OID 2476705)
|
||||
-- Name: usage_bucket_by_user usage_bucket_by_user_unique; Type: CONSTRAINT; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY s3billing.usage_bucket_by_user
|
||||
ADD CONSTRAINT usage_bucket_by_user_unique UNIQUE (bucketid, date_start, date_end, user_id, category_id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3288 (class 2606 OID 2160703)
|
||||
-- Name: usage_stat_summary usage_stat_summary_pkey; Type: CONSTRAINT; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY s3billing.usage_stat_summary
|
||||
ADD CONSTRAINT usage_stat_summary_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3286 (class 2606 OID 2160696)
|
||||
-- Name: usage_stat_total usage_stat_total_pkey; Type: CONSTRAINT; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY s3billing.usage_stat_total
|
||||
ADD CONSTRAINT usage_stat_total_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3295 (class 2606 OID 2160758)
|
||||
-- Name: user_info user_info_pkey; Type: CONSTRAINT; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY s3billing.user_info
|
||||
ADD CONSTRAINT user_info_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3292 (class 2606 OID 2160719)
|
||||
-- Name: user_quota_bucket user_quota_bucket_pkey; Type: CONSTRAINT; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY s3billing.user_quota_bucket
|
||||
ADD CONSTRAINT user_quota_bucket_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3275 (class 2606 OID 2160666)
|
||||
-- Name: zone_group zone_group_pkey; Type: CONSTRAINT; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY s3billing.zone_group
|
||||
ADD CONSTRAINT zone_group_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3276 (class 1259 OID 2474077)
|
||||
-- Name: bucket_info_name_idx; Type: INDEX; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
CREATE INDEX bucket_info_name_idx ON s3billing.bucket_info USING btree (name);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3279 (class 1259 OID 2474078)
|
||||
-- Name: bucket_info_placement_id_idx; Type: INDEX; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
CREATE INDEX bucket_info_placement_id_idx ON s3billing.bucket_info USING btree (placement_id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3271 (class 1259 OID 2474094)
|
||||
-- Name: bucket_stat_owner_idx; Type: INDEX; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
CREATE INDEX bucket_stat_owner_idx ON s3billing.bucket_stat USING btree (owner);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3296 (class 1259 OID 2474445)
|
||||
-- Name: category_name_idx; Type: INDEX; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
CREATE UNIQUE INDEX category_name_idx ON s3billing.category USING btree (name);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3280 (class 1259 OID 2474468)
|
||||
-- Name: placement_name_idx; Type: INDEX; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
CREATE UNIQUE INDEX placement_name_idx ON s3billing.placement USING btree (name);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3293 (class 1259 OID 2474438)
|
||||
-- Name: user_info_name_idx; Type: INDEX; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
CREATE INDEX user_info_name_idx ON s3billing.user_info USING btree (name);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3447 (class 0 OID 0)
|
||||
-- Dependencies: 230
|
||||
-- Name: TABLE bucket_info; Type: ACL; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
GRANT SELECT ON TABLE s3billing.bucket_info TO grafanabilling;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3449 (class 0 OID 0)
|
||||
-- Dependencies: 226
|
||||
-- Name: TABLE bucket_stat; Type: ACL; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
GRANT SELECT ON TABLE s3billing.bucket_stat TO grafanabilling;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3450 (class 0 OID 0)
|
||||
-- Dependencies: 245
|
||||
-- Name: TABLE category; Type: ACL; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
GRANT SELECT ON TABLE s3billing.category TO grafanabilling;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3452 (class 0 OID 0)
|
||||
-- Dependencies: 225
|
||||
-- Name: TABLE goose_db_version; Type: ACL; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
GRANT SELECT ON TABLE s3billing.goose_db_version TO grafanabilling;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3453 (class 0 OID 0)
|
||||
-- Dependencies: 234
|
||||
-- Name: TABLE index_type; Type: ACL; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
GRANT SELECT ON TABLE s3billing.index_type TO grafanabilling;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3455 (class 0 OID 0)
|
||||
-- Dependencies: 232
|
||||
-- Name: TABLE placement; Type: ACL; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
GRANT SELECT ON TABLE s3billing.placement TO grafanabilling;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3457 (class 0 OID 0)
|
||||
-- Dependencies: 239
|
||||
-- Name: TABLE usage_bucket_by_user; Type: ACL; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
GRANT SELECT ON TABLE s3billing.usage_bucket_by_user TO grafanabilling;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3458 (class 0 OID 0)
|
||||
-- Dependencies: 238
|
||||
-- Name: TABLE usage_stat_summary; Type: ACL; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
GRANT SELECT ON TABLE s3billing.usage_stat_summary TO grafanabilling;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3460 (class 0 OID 0)
|
||||
-- Dependencies: 236
|
||||
-- Name: TABLE usage_stat_total; Type: ACL; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
GRANT SELECT ON TABLE s3billing.usage_stat_total TO grafanabilling;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3462 (class 0 OID 0)
|
||||
-- Dependencies: 243
|
||||
-- Name: TABLE user_info; Type: ACL; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
GRANT SELECT ON TABLE s3billing.user_info TO grafanabilling;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3464 (class 0 OID 0)
|
||||
-- Dependencies: 241
|
||||
-- Name: TABLE user_quota_bucket; Type: ACL; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
GRANT SELECT ON TABLE s3billing.user_quota_bucket TO grafanabilling;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3466 (class 0 OID 0)
|
||||
-- Dependencies: 228
|
||||
-- Name: TABLE zone_group; Type: ACL; Schema: s3billing; Owner: s3billing
|
||||
--
|
||||
|
||||
GRANT SELECT ON TABLE s3billing.zone_group TO grafanabilling;
|
||||
|
||||
|
||||
-- Completed on 2025-09-15 09:50:59
|
||||
|
||||
--
|
||||
-- PostgreSQL database dump complete
|
||||
--
|
||||
|
||||
@@ -1,278 +0,0 @@
|
||||
--
|
||||
-- PostgreSQL database dump
|
||||
--
|
||||
|
||||
-- Dumped from database version 16.0
|
||||
-- Dumped by pg_dump version 16.4
|
||||
|
||||
-- Started on 2025-09-15 09:53:16
|
||||
|
||||
SET statement_timeout = 0;
|
||||
SET lock_timeout = 0;
|
||||
SET idle_in_transaction_session_timeout = 0;
|
||||
SET client_encoding = 'UTF8';
|
||||
SET standard_conforming_strings = on;
|
||||
SELECT pg_catalog.set_config('search_path', '', false);
|
||||
SET check_function_bodies = false;
|
||||
SET xmloption = content;
|
||||
SET client_min_messages = warning;
|
||||
SET row_security = off;
|
||||
|
||||
SET default_tablespace = '';
|
||||
|
||||
SET default_table_access_method = heap;
|
||||
|
||||
--
|
||||
-- TOC entry 222 (class 1259 OID 1893983)
|
||||
-- Name: capacity_resource; Type: TABLE; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
|
||||
CREATE TABLE ngcloud_ru.capacity_resource (
|
||||
vdc_id uuid NOT NULL,
|
||||
"timestamp" timestamp with time zone NOT NULL,
|
||||
cpu_allocated integer NOT NULL,
|
||||
cpu_limit integer NOT NULL,
|
||||
cpu_reserved integer NOT NULL,
|
||||
cpu_used integer NOT NULL,
|
||||
cpu_speed integer NOT NULL,
|
||||
mem_allocated integer NOT NULL,
|
||||
mem_limit integer NOT NULL,
|
||||
mem_reserved integer NOT NULL,
|
||||
mem_used integer NOT NULL
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE ngcloud_ru.capacity_resource OWNER TO vc_billing;
|
||||
|
||||
--
|
||||
-- TOC entry 223 (class 1259 OID 1893993)
|
||||
-- Name: capacity_storage; Type: TABLE; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
|
||||
CREATE TABLE ngcloud_ru.capacity_storage (
|
||||
vdc_id uuid NOT NULL,
|
||||
storage_profile_types_id integer NOT NULL,
|
||||
"timestamp" timestamp with time zone NOT NULL,
|
||||
id uuid NOT NULL,
|
||||
"limit" integer NOT NULL,
|
||||
used integer NOT NULL
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE ngcloud_ru.capacity_storage OWNER TO vc_billing;
|
||||
|
||||
--
|
||||
-- TOC entry 220 (class 1259 OID 1893965)
|
||||
-- Name: storage_profile_types; Type: TABLE; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
|
||||
CREATE TABLE ngcloud_ru.storage_profile_types (
|
||||
id integer NOT NULL,
|
||||
name character varying(255) NOT NULL
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE ngcloud_ru.storage_profile_types OWNER TO vc_billing;
|
||||
|
||||
--
|
||||
-- TOC entry 219 (class 1259 OID 1893964)
|
||||
-- Name: storage_profile_types_id_seq; Type: SEQUENCE; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
|
||||
CREATE SEQUENCE ngcloud_ru.storage_profile_types_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
ALTER SEQUENCE ngcloud_ru.storage_profile_types_id_seq OWNER TO vc_billing;
|
||||
|
||||
--
|
||||
-- TOC entry 3413 (class 0 OID 0)
|
||||
-- Dependencies: 219
|
||||
-- Name: storage_profile_types_id_seq; Type: SEQUENCE OWNED BY; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
|
||||
ALTER SEQUENCE ngcloud_ru.storage_profile_types_id_seq OWNED BY ngcloud_ru.storage_profile_types.id;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 218 (class 1259 OID 1893959)
|
||||
-- Name: tenant; Type: TABLE; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
|
||||
CREATE TABLE ngcloud_ru.tenant (
|
||||
id uuid NOT NULL,
|
||||
name character varying(255) NOT NULL,
|
||||
wzcode bigint
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE ngcloud_ru.tenant OWNER TO vc_billing;
|
||||
|
||||
--
|
||||
-- TOC entry 221 (class 1259 OID 1893973)
|
||||
-- Name: vdc; Type: TABLE; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
|
||||
CREATE TABLE ngcloud_ru.vdc (
|
||||
id uuid NOT NULL,
|
||||
tenant_id uuid NOT NULL,
|
||||
name character varying(255) NOT NULL
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE ngcloud_ru.vdc OWNER TO vc_billing;
|
||||
|
||||
--
|
||||
-- TOC entry 3245 (class 2604 OID 1893968)
|
||||
-- Name: storage_profile_types id; Type: DEFAULT; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY ngcloud_ru.storage_profile_types ALTER COLUMN id SET DEFAULT nextval('ngcloud_ru.storage_profile_types_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3255 (class 2606 OID 1893987)
|
||||
-- Name: capacity_resource capacity_resource_pkey; Type: CONSTRAINT; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY ngcloud_ru.capacity_resource
|
||||
ADD CONSTRAINT capacity_resource_pkey PRIMARY KEY (vdc_id, "timestamp");
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3257 (class 2606 OID 1893997)
|
||||
-- Name: capacity_storage capacity_storage_pkey; Type: CONSTRAINT; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY ngcloud_ru.capacity_storage
|
||||
ADD CONSTRAINT capacity_storage_pkey PRIMARY KEY (vdc_id, id, "timestamp");
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3249 (class 2606 OID 1893972)
|
||||
-- Name: storage_profile_types storage_profile_types_name_key; Type: CONSTRAINT; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY ngcloud_ru.storage_profile_types
|
||||
ADD CONSTRAINT storage_profile_types_name_key UNIQUE (name);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3251 (class 2606 OID 1893970)
|
||||
-- Name: storage_profile_types storage_profile_types_pkey; Type: CONSTRAINT; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY ngcloud_ru.storage_profile_types
|
||||
ADD CONSTRAINT storage_profile_types_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3247 (class 2606 OID 1893963)
|
||||
-- Name: tenant tenant_pkey; Type: CONSTRAINT; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY ngcloud_ru.tenant
|
||||
ADD CONSTRAINT tenant_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3253 (class 2606 OID 1893977)
|
||||
-- Name: vdc vdc_pkey; Type: CONSTRAINT; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY ngcloud_ru.vdc
|
||||
ADD CONSTRAINT vdc_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3259 (class 2606 OID 1893988)
|
||||
-- Name: capacity_resource capacity_resource_vdc_id_fkey; Type: FK CONSTRAINT; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY ngcloud_ru.capacity_resource
|
||||
ADD CONSTRAINT capacity_resource_vdc_id_fkey FOREIGN KEY (vdc_id) REFERENCES ngcloud_ru.vdc(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3260 (class 2606 OID 1894003)
|
||||
-- Name: capacity_storage capacity_storage_storage_profile_types_id_fkey; Type: FK CONSTRAINT; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY ngcloud_ru.capacity_storage
|
||||
ADD CONSTRAINT capacity_storage_storage_profile_types_id_fkey FOREIGN KEY (storage_profile_types_id) REFERENCES ngcloud_ru.storage_profile_types(id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3261 (class 2606 OID 1893998)
|
||||
-- Name: capacity_storage capacity_storage_vdc_id_fkey; Type: FK CONSTRAINT; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY ngcloud_ru.capacity_storage
|
||||
ADD CONSTRAINT capacity_storage_vdc_id_fkey FOREIGN KEY (vdc_id) REFERENCES ngcloud_ru.vdc(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3258 (class 2606 OID 1893978)
|
||||
-- Name: vdc vdc_tenant_id_fkey; Type: FK CONSTRAINT; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY ngcloud_ru.vdc
|
||||
ADD CONSTRAINT vdc_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES ngcloud_ru.tenant(id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3410 (class 0 OID 0)
|
||||
-- Dependencies: 222
|
||||
-- Name: TABLE capacity_resource; Type: ACL; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
|
||||
GRANT SELECT ON TABLE ngcloud_ru.capacity_resource TO grafanabilling;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3411 (class 0 OID 0)
|
||||
-- Dependencies: 223
|
||||
-- Name: TABLE capacity_storage; Type: ACL; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
|
||||
GRANT SELECT ON TABLE ngcloud_ru.capacity_storage TO grafanabilling;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3412 (class 0 OID 0)
|
||||
-- Dependencies: 220
|
||||
-- Name: TABLE storage_profile_types; Type: ACL; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
|
||||
GRANT SELECT ON TABLE ngcloud_ru.storage_profile_types TO grafanabilling;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3414 (class 0 OID 0)
|
||||
-- Dependencies: 218
|
||||
-- Name: TABLE tenant; Type: ACL; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
|
||||
GRANT SELECT ON TABLE ngcloud_ru.tenant TO grafanabilling;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3415 (class 0 OID 0)
|
||||
-- Dependencies: 221
|
||||
-- Name: TABLE vdc; Type: ACL; Schema: ngcloud_ru; Owner: vc_billing
|
||||
--
|
||||
|
||||
GRANT SELECT ON TABLE ngcloud_ru.vdc TO grafanabilling;
|
||||
|
||||
|
||||
-- Completed on 2025-09-15 09:53:18
|
||||
|
||||
--
|
||||
-- PostgreSQL database dump complete
|
||||
--
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
CREATE INDEX ON ngcloud_ru.capacity_resource (timestamp);
|
||||
CREATE INDEX ON ngcloud_ru.capacity_storage (timestamp);
|
||||
|
||||
CREATE INDEX ON s3billing.bucket_stat (timestamp_addition);
|
||||
CREATE INDEX ON s3billing.usage_bucket_by_user (time);
|
||||
|
||||
CREATE INDEX ON gpu.vm (dt_load);
|
||||
CREATE INDEX ON gpu.vm_power_state (ts);
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"ds_rpt_class": "org.postgresql.Driver",
|
||||
"ds_rpt_connectionString": "jdbc:postgresql://write.09d78921-77a7-401a-b2cb-5ca11be850a0.services.ngcloud.ru:5432/rpt",
|
||||
"ds_rpt_username": "appserver",
|
||||
"ds_rpt_password": "encrypted:********",
|
||||
"ds_rpt_connectionLimit": "5",
|
||||
"IDP_CLIENT_SECRET": "********",
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
REM set Windows env
|
||||
setx rpt_class org.postgresql.Driver /M
|
||||
setx rpt_connectionString jdbc:postgresql://write.09d78921-77a7-401a-b2cb-5ca11be850a0.services.ngcloud.ru:5432/rpt /M
|
||||
setx rpt_username appserver /M
|
||||
setx rpt_password encrypted:******** /M
|
||||
setx rpt_connectionLimit 5 /M
|
||||
|
||||
setx IDP_CLIENT_SECRET ******** /M
|
||||
|
||||
pause
|
||||
@@ -1,281 +0,0 @@
|
||||
<cfimport prefix="m" taglib="../lib"/>
|
||||
<cfimport prefix="d" taglib="../lib/data"/>
|
||||
|
||||
<cfparam name="ATTRIBUTES.dt_finish" type="date" default=#createDateTime(year(Now()),month(Now()),1,0,0,0)#/>
|
||||
<cfparam name="ATTRIBUTES.dt_start" type="date" default=#dateAdd('m',-1,ATTRIBUTES.dt_finish)#/>
|
||||
<cfparam name="ATTRIBUTES.output" type="string" default="report"/>
|
||||
<cfparam name="ATTRIBUTES.debug" type="boolean" default=false/>
|
||||
|
||||
<cfset hours=dateDiff('h',dt_start,dt_finish)/>
|
||||
<cfset tenant_wz_index=val(mid(request.auth.wz,3,5))/><!--- cut off WZ --->
|
||||
|
||||
|
||||
<!--- QoQ does not support join syntax, at least of Lucee 5.4--->
|
||||
|
||||
|
||||
<!--- Для начала выкатываем просто кусок каталога, не фильтруя по спеке (которой иногда нет) --->
|
||||
<cfquery name="qSpec">
|
||||
select * from (
|
||||
values
|
||||
('Объектное хранилище S3 CEPH','Дисковое пространство: Объем хранения','paas.s3.ceph.vol-m','ГБайт',1.80,0)
|
||||
,('Объектное хранилище S3 CEPH','Исходящий трафик','paas.s3.ceph.trf-m','ГБайт',1.50,0)
|
||||
,('Объектное хранилище S3 CEPH','Запросы GET, HEAD, OPTIONS','paas.s3.ceph.get-m','10тыс.шт.',0.35,0)
|
||||
,('Объектное хранилище S3 CEPH','Запросы PUT, POST, PATCH','paas.s3.ceph.put-m','10тыс.шт.',4.50,0)
|
||||
) as
|
||||
s (svc, component, code, unit, price, discount)
|
||||
order by code
|
||||
</cfquery>
|
||||
|
||||
|
||||
<!--- Нужно еще реализовать в модели данных политики бесплатного минимума --->
|
||||
<cfquery name="qComputing">
|
||||
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 = <cfqueryparam cfsqltype="cf_sql_integer" value=#tenant_wz_index#/>
|
||||
AND capacity_resource.timestamp >= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#ATTRIBUTES.dt_start#/>
|
||||
AND capacity_resource.timestamp < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#ATTRIBUTES.dt_finish#/>
|
||||
group by tenant.wzcode, vdc.name
|
||||
order by tenant.wzcode, vdc.name;
|
||||
</cfquery>
|
||||
|
||||
<cfif (ATTRIBUTES.debug)>
|
||||
<cfdump var=#qComputing#/>
|
||||
<cfflush/>
|
||||
</cfif>
|
||||
|
||||
<cfquery name="qComputingAge">
|
||||
select max(capacity_resource.timestamp) as dt_load from ngcloud_ru.capacity_resource
|
||||
</cfquery>
|
||||
|
||||
|
||||
<!--- переделать storage_profile_types с расшифровкой ssd, sata, можно прямо до каталожного кода --->
|
||||
<cfquery name="qStorage">
|
||||
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 = <cfqueryparam cfsqltype="cf_sql_integer" value=#tenant_wz_index#/>
|
||||
AND capacity_storage.timestamp >= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#ATTRIBUTES.dt_start#/>
|
||||
AND capacity_storage.timestamp < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#ATTRIBUTES.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="rpt">
|
||||
select max(capacity_storage.timestamp) as dt_load from ngcloud_ru.capacity_storage
|
||||
</cfquery>
|
||||
|
||||
<cfif (ATTRIBUTES.debug)>
|
||||
<cfdump var=#qStorage#/>
|
||||
<cfflush/>
|
||||
</cfif>
|
||||
|
||||
<!---
|
||||
"placement" "size_gb" "get_10k" "put_10k" "bytes_sent_gb"
|
||||
HOT_FREE_LIMIT 1 10 1 100
|
||||
--->
|
||||
<!--- надо дисконтировать не ГБ-часы а ГБ-месяцы --->
|
||||
<cfquery name="qS3Vol">
|
||||
select /* *** ниже дублирование кода агрегации - round ceil etc, обратить внимание при правке */
|
||||
(sum(bucket_stat.usage_rgw_main_size_actual)/<cfqueryparam cfsqltype="cf_sql_integer" value=#hours#/>) as vol_B
|
||||
,ceil(sum(bucket_stat.usage_rgw_main_size_actual)/<cfqueryparam cfsqltype="cf_sql_integer" value=#hours#/>/1024/1024/1024) as vol_GB
|
||||
,greatest(ceil(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.owner = <cfqueryparam cfsqltype="cf_sql_varchar" value=#tenant_wz_index#/>
|
||||
AND bucket_stat.timestamp_addition >= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#ATTRIBUTES.dt_start#/>
|
||||
AND bucket_stat.timestamp_addition < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#ATTRIBUTES.dt_finish#/>
|
||||
group by bucket_stat.owner, bucket_stat.placement_id
|
||||
order by bucket_stat.owner, bucket_stat.placement_id;
|
||||
</cfquery>
|
||||
|
||||
<cfif (ATTRIBUTES.debug)>
|
||||
<cfdump var=#qS3Vol#/>
|
||||
<cfflush/>
|
||||
</cfif>
|
||||
|
||||
<cfquery name="qS3VolAge">
|
||||
select max(timestamp_addition) as dt_load from s3billing.bucket_stat
|
||||
</cfquery>
|
||||
|
||||
<cfquery name="qS3OpsTrf">
|
||||
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 user_info.name = <cfqueryparam cfsqltype="cf_sql_varchar" value=#tenant_wz_index#/>
|
||||
AND usage_bucket_by_user.time >= <cfqueryparam cfsqltype="cf_sql_timestamp" value=#ATTRIBUTES.dt_start#/>
|
||||
AND usage_bucket_by_user.time < <cfqueryparam cfsqltype="cf_sql_timestamp" value=#ATTRIBUTES.dt_finish#/>
|
||||
group by user_info.name, bucket_info.placement_id
|
||||
order by user_info.name, bucket_info.placement_id;
|
||||
</cfquery>
|
||||
|
||||
<cfif (ATTRIBUTES.debug)>
|
||||
<cfdump var=#qS3OpsTrf#/>
|
||||
<cfflush/>
|
||||
</cfif>
|
||||
|
||||
<cfquery name="qS3OpsTrfAge">
|
||||
select max(time) as dt_load from s3billing.usage_bucket_by_user
|
||||
</cfquery>
|
||||
|
||||
|
||||
<cfquery name="qUnifiedMetric" dbType="query">
|
||||
select wz, code || '.vcpu-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 (ATTRIBUTES.debug)>
|
||||
<cfdump var=#qUnifiedMetric#/>
|
||||
<cfflush/>
|
||||
</cfif>
|
||||
|
||||
<cfquery name="qCharge" dbType="query">
|
||||
SELECT
|
||||
<d:field_set titleMapOut="titleMap" lengthOut="fieldCount">
|
||||
<d:field title="Артикул">s.code</d:field>
|
||||
<d:field title="Услуга">s.svc</d:field>
|
||||
<d:field title="Компонент">s.component</d:field>
|
||||
<d:field title="Кол-во (метрика)" cfSqlType="CF_SQL_NUMERIC">m.chargeable_metric</d:field>
|
||||
<d:field title="Ед.изм.">s.unit</d:field>
|
||||
<d:field title="Цена &##8381; с НДС" cfSqlType="CF_SQL_NUMERIC">s.price*(100-s.discount)/100 as discounted_price</d:field>
|
||||
<d:field title="Стоимость &##8381; с НДС" cfSqlType="CF_SQL_NUMERIC">s.price*(100-s.discount)/100*m.chargeable_metric as charge</d:field>
|
||||
<!--- <d:field title="Дата НОУ" cfSqlType="CF_SQL_TIMESTAMP">s.dt_from</d:field> --->
|
||||
<!--- <d:field title="Дата оконч." cfSqlType="CF_SQL_TIMESTAMP">s.dt_to</d:field>
|
||||
<d:field title="Ключ строки">s.line_key</d:field> --->
|
||||
<d:field title="GPL с НДС" cfSqlType="CF_SQL_NUMERIC">s.price</d:field>
|
||||
<d:field title="Скидка%" cfSqlType="CF_SQL_NUMERIC">s.discount</d:field>
|
||||
<d:field title="Сырая метрика" cfSqlType="CF_SQL_NUMERIC">m.raw_metric</d:field>
|
||||
<d:field title="Приведенная метрика" cfSqlType="CF_SQL_NUMERIC">m.metric</d:field>
|
||||
|
||||
<!--- <d:field title="Клиентс. назв.">s.user_description</d:field> --->
|
||||
</d:field_set>
|
||||
FROM qSpec as s, qUnifiedMetric as m
|
||||
WHERE m.wz=<cfqueryparam cfsqltype="cf_sql_varchar" value=#request.auth.wz#/> AND s.code=m.code
|
||||
order by s.code
|
||||
</cfquery>
|
||||
|
||||
<cfset var report={}/>
|
||||
|
||||
<cfset report.qComputingAge = qComputingAge/>
|
||||
<cfset report.qStorageAge = qStorageAge/>
|
||||
<cfset report.qS3VolAge = qS3VolAge/>
|
||||
<cfset report.qS3OpsTrfAge = qS3OpsTrfAge/>
|
||||
<cfset report.qCharge = qCharge/>
|
||||
<cfset report.chargeTitleMap = titleMap/>
|
||||
<cfset report.chargeFieldCount = fieldCount/>
|
||||
|
||||
<cfset "CALLER.#ATTRIBUTES.output#" = report/>
|
||||
|
||||
<cfexit method="exittag"/>
|
||||
@@ -1,159 +0,0 @@
|
||||
<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)/>
|
||||
<cfset tenant_wz_index=val(mid(request.auth.wz,3,5))/><!--- cut off WZ --->
|
||||
<cfset tenant_wz_index="00169"/><!--- cut off WZ --->
|
||||
|
||||
|
||||
<cfif isDefined("output_xls")><cfmodule template="mod/payg.cfm"
|
||||
dt_finish=#dt_finish#
|
||||
dt_start=#dt_start#
|
||||
tenant_wz_index=#tenant_wz_index#
|
||||
output="report"
|
||||
debug=#isDefined("DEBUG")#
|
||||
/><layout:xml qRead=#report.qCharge# titleMap=#report.chargeTitleMap# filename="#pageInfo.entity#.xml"/>
|
||||
<cfabort/>
|
||||
</cfif><cfif isDefined("output_json")><cfmodule template="mod/payg.cfm"
|
||||
dt_finish=#dt_finish#
|
||||
dt_start=#dt_start#
|
||||
tenant_wz_index=#tenant_wz_index#
|
||||
output="report"
|
||||
debug=#isDefined("DEBUG")#
|
||||
/><!--- <cfdump var=#report#/><cfabort/> ---><layout:json qRead=#report.qCharge# titleMap=#report.chargeTitleMap# filename="#pageInfo.entity#.json"/>
|
||||
<cfabort/>
|
||||
</cfif><!---
|
||||
---><layout:page section="header" pageInfo=#pageInfo#>
|
||||
|
||||
<layout:attribute name="title">
|
||||
<cfoutput><b>Отчет по PAYG</b> #request.auth.wz#</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> --->
|
||||
|
||||
<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>
|
||||
|
||||
|
||||
|
||||
<cfflush/>
|
||||
|
||||
<cfmodule template="mod/payg.cfm"
|
||||
dt_finish=#dt_finish#
|
||||
dt_start=#dt_start#
|
||||
tenant_wz_index=#tenant_wz_index#
|
||||
output="report"
|
||||
debug=#isDefined("DEBUG")#
|
||||
/>
|
||||
|
||||
Часов в периоде: <b>#hours#</b> Строк в отчете: <b>#report.qCharge.recordCount#</b><br/>
|
||||
Актуальность данных:
|
||||
VCD Computing: <b>#dateFormat(report.qComputingAge.dt_load,'YYYY-MM-DD')# #timeFormat(report.qComputingAge.dt_load,'HH:MM:SS')#</b>
|
||||
VCD Storage: <b>#dateFormat(report.qStorageAge.dt_load,'YYYY-MM-DD')# #timeFormat(report.qStorageAge.dt_load,'HH:MM:SS')#</b>
|
||||
S3 хранение: <b>#dateFormat(report.qS3VolAge.dt_load,'YYYY-MM-DD')# #timeFormat(report.qS3VolAge.dt_load,'HH:MM:SS')#</b>
|
||||
S3 операции и трафик: <b>#dateFormat(report.qS3OpsTrfAge.dt_load,'YYYY-MM-DD')# #timeFormat(report.qS3OpsTrfAge.dt_load,'HH:MM:SS')#</b>
|
||||
|
||||
<br/>
|
||||
<a href="#request.thisPage#?output_xls" title="экспорт в Excel" style="margin-left:.5em; height:100%;" target="_blank"><img src="img/xls.gif" style="vertical-align:text-bottom;"/></a>
|
||||
|
||||
<a href="#request.thisPage#?output_json" 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>
|
||||
</cfoutput>
|
||||
<table class="worktable">
|
||||
<thead>
|
||||
<td width="1%"></td>
|
||||
<!--- <th width="3%">WZ</th> --->
|
||||
<th width="7%">Артикул</th>
|
||||
<th width="7%">Кол-во (метрика)</th>
|
||||
<th width="3%">Ед.изм.</th>
|
||||
<th width="3%">Цена ₽ со скид., с НДС</th>
|
||||
<th width="3%">Стоимость ₽ с НДС</th>
|
||||
|
||||
<td width="3%"> </td>
|
||||
|
||||
<td width="10%">Услуга</td>
|
||||
<td width="10%">Компонент</td>
|
||||
<!--- <td width="10%">Клиентс. назв.</td> --->
|
||||
|
||||
<td width="3%">GPL с НДС</td>
|
||||
<td width="3%">Скидка%</td>
|
||||
|
||||
<!--- <td width="6%">Дата НОУ</td>
|
||||
<td width="6%">Дата оконч.</td>
|
||||
|
||||
<td width="3%">Ключ строки</td> --->
|
||||
<!--- <td width="3%">Сырая метрика</td> --->
|
||||
<td width="3%">Оплачиваемый объем</td>
|
||||
|
||||
<!--- <td width="5%">Договор</td>
|
||||
<td width="10%">Допник</td>
|
||||
<td width="10%">Сделка</td> --->
|
||||
|
||||
</thead>
|
||||
|
||||
<cfoutput query="report.qCharge" group="svc">
|
||||
<cfset var acc=0/>
|
||||
<tr>
|
||||
<td bgcolor="##ccc"></td>
|
||||
<td bgcolor="##ccc" colspan="5" class="b"> #svc#</td>
|
||||
<td></td>
|
||||
<td bgcolor="##ccc" colspan="99"></td>
|
||||
</tr>
|
||||
<cfoutput>
|
||||
<cfset acc=acc+charge/>
|
||||
<tr>
|
||||
<td>#currentRow#</a></td>
|
||||
|
||||
<td>#code#</td>
|
||||
<td class="r" style="font-size:120%; padding:0 1em;">#chargeable_metric#</td>
|
||||
<td class="c" style="font-size:90%;">#unit#</td>
|
||||
<td class="r">#discounted_price#</td>
|
||||
<td class="r">#charge#</td>
|
||||
|
||||
<td></td>
|
||||
|
||||
<td>#svc#</td>
|
||||
<td>#component#</td>
|
||||
<!--- <td>#user_description#</td> --->
|
||||
|
||||
<td class="r">#price#</td>
|
||||
<td class="r">#discount#</td>
|
||||
|
||||
<td class="r">#metric#</td>
|
||||
|
||||
</tr>
|
||||
</cfoutput>
|
||||
<tr>
|
||||
<td bgcolor="##eee" style="border-bottom:2px solid gray;"></td>
|
||||
<td bgcolor="##eee" colspan="4" class="r" style="border-bottom:2px solid gray;"><b>Итого</b> #svc#:</td>
|
||||
<td bgcolor="##eee" colspan="1" class="r b" style="border-bottom:2px solid gray;">#NumFmt(acc,2)#</td>
|
||||
<td colspan="14" style="border-bottom:2px solid gray;"></td>
|
||||
</tr >
|
||||
</cfoutput>
|
||||
|
||||
</table>
|
||||
<!--- <cfdump var=#qCharge#/> --->
|
||||
|
||||
|
||||
<layout:page section="footer"/>
|
||||
|
||||
<!--- select * from s3billing.billing_per_user_fix_pl('2025-05-01 00:00:00','2025-06-01 00:00:00','1395'); --->
|
||||
|
||||
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 6.1 KiB |
@@ -1,47 +0,0 @@
|
||||
<?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>
|
||||
|
Before Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 69 B |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 174 B |
|
Before Width: | Height: | Size: 173 B |
|
Before Width: | Height: | Size: 173 B |
|
Before Width: | Height: | Size: 180 B |
|
Before Width: | Height: | Size: 179 B |
|
Before Width: | Height: | Size: 180 B |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 255 B |
|
Before Width: | Height: | Size: 8.9 KiB |
@@ -1,16 +0,0 @@
|
||||
<?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>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 141 B |
|
Before Width: | Height: | Size: 222 B |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1023 B |
|
Before Width: | Height: | Size: 889 B |
|
Before Width: | Height: | Size: 81 B |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 15 KiB |
@@ -1,16 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 498 B |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 431 B |
|
Before Width: | Height: | Size: 725 B |
|
Before Width: | Height: | Size: 996 B |
|
Before Width: | Height: | Size: 743 B |
|
Before Width: | Height: | Size: 972 B |
|
Before Width: | Height: | Size: 517 B |
|
Before Width: | Height: | Size: 665 B |
|
Before Width: | Height: | Size: 692 B |
|
Before Width: | Height: | Size: 271 B |
|
Before Width: | Height: | Size: 691 B |
|
Before Width: | Height: | Size: 71 B |
|
Before Width: | Height: | Size: 71 B |
|
Before Width: | Height: | Size: 537 B |
|
Before Width: | Height: | Size: 305 B |
|
Before Width: | Height: | Size: 350 B |
|
Before Width: | Height: | Size: 346 B |
|
Before Width: | Height: | Size: 1000 B |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 54 B |
|
Before Width: | Height: | Size: 54 B |
|
Before Width: | Height: | Size: 103 B |
|
Before Width: | Height: | Size: 241 B |
|
Before Width: | Height: | Size: 362 B |
|
Before Width: | Height: | Size: 243 B |
|
Before Width: | Height: | Size: 97 KiB |
|
Before Width: | Height: | Size: 51 B |
|
Before Width: | Height: | Size: 84 B |
|
Before Width: | Height: | Size: 990 B |
@@ -1,358 +0,0 @@
|
||||
<cfscript>
|
||||
/* Все глобальные функции экспортированы в request scope */
|
||||
function plain2htm(s) {
|
||||
return replace(replace(s, chr(13),'',"ALL"),chr(10),'<br/>', "ALL");
|
||||
}
|
||||
request.plain2htm = plain2htm;
|
||||
|
||||
function htm2plain(s) {
|
||||
return replaceNoCase(s, '<br/>', '#chr(13)##chr(10)#', "ALL");
|
||||
}
|
||||
request.htm2plain = htm2plain;
|
||||
|
||||
function cleanHtm(s) {
|
||||
return replaceList(s, '<,>,"', '<,>,"');
|
||||
}
|
||||
request.cleanHtm = cleanHtm;
|
||||
|
||||
function clean4CDATA(s) {
|
||||
LF = chr(10);
|
||||
return replaceNoCase(replaceList(s, '[,]', '&91;,&93;'),"<br>",LF,"ALL");
|
||||
}
|
||||
request.clean4CDATA = clean4CDATA;
|
||||
|
||||
function numFmt(num, decimalPlaces = 0){
|
||||
var sFormat = ",";
|
||||
if (decimalPlaces GT 0) {sFormat = sFormat & "." & repeatString("0", decimalPlaces);}
|
||||
return replace(NumberFormat(num, sFormat), ",", " ", "ALL");
|
||||
}
|
||||
request.numFmt = numFmt;
|
||||
|
||||
function nFmt(num, decimalPlaces = 2){
|
||||
if (num EQ 0) return "";
|
||||
return numFmt(num, decimalPlaces);
|
||||
}
|
||||
request.nFmt = nFmt;
|
||||
|
||||
function dateFmt(date, sFormat = 'YYYY-MM-DD'){
|
||||
return dateFormat(date, sFormat);
|
||||
}
|
||||
request.dateFmt = dateFmt;
|
||||
|
||||
function dateTimeFmt(date, sDateFormat = 'YYYY-MM-DD', sTimeFormat='HH:MM'){
|
||||
return dateFormat(date, sDateFormat) & ' ' & timeFormat(date, sTimeFormat);
|
||||
}
|
||||
request.dateTimeFmt = dateTimeFmt;
|
||||
|
||||
function timeFmt(date, sFormat = 'HH:MM'){
|
||||
return timeFormat(date, sFormat);
|
||||
}
|
||||
request.timeFmt = timeFmt;
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
function usrAuthenticated() {
|
||||
return structKeyExists(request, "auth");
|
||||
}
|
||||
request.usrAuthenticated = usrAuthenticated;
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
function filterOn(filter) {
|
||||
return (isStruct(filter) AND NOT structIsEmpty(filter));
|
||||
}
|
||||
request.filterOn = filterOn;
|
||||
|
||||
function stripWhiteSpace(sNumber) {
|
||||
return reReplace(sNumber, "[[:space:]]", "", "ALL");
|
||||
}
|
||||
request.stripWhiteSpace = stripWhiteSpace;
|
||||
/*
|
||||
// never used
|
||||
function cleanNumber(sNumber) {
|
||||
var s = reReplace(sNumber, "[[:space:]]", "", "ALL");
|
||||
if ( find(",", s) ) { //watch argument order!!!
|
||||
// assume Russian format with decimal comma and spaces for thousand separator
|
||||
return replace(s, ",", ".");
|
||||
} else {
|
||||
// assume English format with decimal point and commas for thousand separator
|
||||
return replace(s, ",", "", "ALL");
|
||||
}
|
||||
}
|
||||
request.cleanNumber = cleanNumber;
|
||||
*/
|
||||
|
||||
/*https://cflib.org/udf/queryColumnToArray*/
|
||||
/**
|
||||
* Takes a selected column of data from a query and converts it into an array.
|
||||
*
|
||||
* @param query The query to scan. (Required)
|
||||
* @param column The name of the column to return data from. (Required)
|
||||
* @return Returns an array.
|
||||
* @author Peter J. Farrell (pjf@maestropublishing.com)
|
||||
* @version 1, July 22, 2005
|
||||
*/
|
||||
function queryColumnToArray(qry, column) {
|
||||
var arr = arrayNew(1);
|
||||
var ii = "";
|
||||
var loop_len = arguments.qry.recordcount;
|
||||
for (ii=1; ii lte loop_len; ii=ii+1) {
|
||||
arrayAppend(arr, arguments.qry[arguments.column][ii]);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
request.queryColumnToArray = queryColumnToArray;
|
||||
|
||||
/* ************************************* */
|
||||
|
||||
function loginPasswordPolicyCheck(usr_id, login, passwd, passwd2) {
|
||||
msg = "";
|
||||
// для старого логина длина не проверяется, все равно ничего не поделаешь
|
||||
if (NOT(usr_id GT 0) AND len(login) LE 3) {
|
||||
msg="Слишком короткий логин (минимальная длина логина 3 символа)";
|
||||
} else {
|
||||
if (passwd NEQ passwd2) {
|
||||
msg="Пароль и подтверждение не совпадают";
|
||||
} else {
|
||||
if (len(passwd) LT "8") msg="Слишком короткий пароль (минимальная длина пароля 8 символов)";
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
request.loginPasswordPolicyCheck = loginPasswordPolicyCheck;
|
||||
|
||||
function i18(label,label_en=label) {
|
||||
//примитивная 2-язычная версия
|
||||
if (request.language EQ 'en') {
|
||||
return label_en;
|
||||
} else {
|
||||
return label;
|
||||
};
|
||||
}
|
||||
request.i18 = i18;
|
||||
|
||||
function passwordHashCreate(password) {
|
||||
return GenerateArgon2Hash('#ARGUMENTS.password#', 'argon2id', 1, 16000, 2);
|
||||
}
|
||||
request.passwordHashCreate = passwordHashCreate;
|
||||
|
||||
function passwordHashCheck(password, passwordHash) {
|
||||
return Argon2CheckHash('#ARGUMENTS.password#', ARGUMENTS.passwordHash, 'argon2id');
|
||||
}
|
||||
request.passwordHashCheck = passwordHashCheck;
|
||||
/*
|
||||
function skuCode(area_code="", abstract_service_code="") {
|
||||
var s="#arguments[1]#.#arguments[2]#";
|
||||
if (arrayLen(arguments) GE 3) {
|
||||
if (len(arguments[3]) GT 0) {
|
||||
s="#s#.#arguments[3]#";
|
||||
} else {
|
||||
s="#s#.0";
|
||||
};
|
||||
};
|
||||
if (arrayLen(arguments) GE 4) {
|
||||
if (len(arguments[4]) GT 0) {
|
||||
s="#s#.#arguments[4]#"
|
||||
}
|
||||
};
|
||||
if (arrayLen(arguments) GE 5) {
|
||||
var pricingModelSuffix=arguments[5];
|
||||
s="#s#-#pricingModelSuffix#";
|
||||
}
|
||||
return s;
|
||||
}
|
||||
request.skuCode = skuCode;
|
||||
*/
|
||||
function roundSafe(a, precision) {
|
||||
return (isNumeric(a) AND isNumeric(precision)) ? round(a,precision) : a;
|
||||
}
|
||||
request.roundSafe = roundSafe;
|
||||
|
||||
function timeUnitLabel(n, value=0, locale="ru") {
|
||||
var labels = ["сек.","мин.","ч.","д.","мес."];
|
||||
if (n LE 5 AND n GE 1) {return labels[n];}
|
||||
else if (n EQ 6) { // в зависимости от числа - "год" г. или "лет" л.
|
||||
var m = value MOD 100;
|
||||
if (m GE 11 AND m LE 20) {
|
||||
return "л.";
|
||||
}
|
||||
m = m MOD 10;
|
||||
if (m GE 1 AND m LE 4) {
|
||||
return "г.";
|
||||
}
|
||||
return "л.";
|
||||
}
|
||||
throw (message="timeUnitLabelRu: index out of bounds", detail="Index must be from 1 to 6");
|
||||
}
|
||||
request.timeUnitLabel = timeUnitLabel;
|
||||
|
||||
function dateDiffVerbose(dateFrom, dateTo, maxParts=6, maxPrecision=1, locale="ru") {
|
||||
// returns formatted datetime interval duration, e.g. 1 hour 5 minutes or 3 years 0 months 12 days
|
||||
//(currently, only Russian supported)
|
||||
//
|
||||
//maxParts specifies, how many parts to display
|
||||
//maxPrecision starts froms seconds: 1=seconds, 2=minutes, 3=hours, 4=days, 5=months, 6=years
|
||||
//if maxPrecision specified is greater than given time interval, output is nothing
|
||||
//locale=ru just for interface, not used
|
||||
//attention: truncates the tail, not rounds
|
||||
//example: request.dateDiffVerbose(Now(),Now()+373.1234567, 3, 1) produces 1 г. 0 мес. 8 д.
|
||||
//example: request.dateDiffVerbose(Now(),Now()+373.1234567, 6, 1) produces 1 г. 0 мес. 8 д. 2 ч. 57 мин. 46 сек.
|
||||
//intended common usage: request.dateDiffVerbose(dateFrom, dateTo, 2, 1) - prints 2 senior parts of the interval,
|
||||
//with presision not better than second
|
||||
//
|
||||
// this is not the same task as converting number of seconds to days-hours-minutes-seconds,
|
||||
// because months contain different number of days, and days number of february depends on year
|
||||
try {
|
||||
if (NOT (isDate(dateFrom) AND isDate(dateTo))) return "";
|
||||
var UNIT_CODES = ["s","n","h","d","m","yyyy"];
|
||||
var start = dateFrom;
|
||||
var finish = dateTo;
|
||||
|
||||
var sOut = "";
|
||||
var nUnits = 0;
|
||||
var nPrintedPositions = 0;
|
||||
var printStart = false;
|
||||
|
||||
for (i=ArrayLen(UNIT_CODES); i GT 0; i=i-1) {
|
||||
nUnits = dateDiff(UNIT_CODES[i], start, finish);
|
||||
start = dateAdd(UNIT_CODES[i], nUnits, start);
|
||||
if (nPrintedPositions GT 0) {nPrintedPositions=nPrintedPositions+1;} //print started, so increment position
|
||||
if (nPrintedPositions GT maxParts) {break;}
|
||||
if (i LT maxPrecision) {break;}
|
||||
if (nUnits NEQ 0 AND nPrintedPositions EQ 0) {nPrintedPositions=1;}
|
||||
if (nPrintedPositions GT 0) {
|
||||
if (len(sOut)) {sOut=sOut & " ";}
|
||||
sOut=sOut & nUnits & " " & request.timeUnitLabel(i, nUnits, "ru");
|
||||
}
|
||||
}
|
||||
return sOut;
|
||||
} catch(e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
request.dateDiffVerbose = dateDiffVerbose;
|
||||
|
||||
/*
|
||||
function secondsToDHMS(nSeconds,partsToKeep) {
|
||||
//format seconds to days-hours-minutes-seconds and truncate to specified precision
|
||||
{
|
||||
days = n / (24 * 3600);
|
||||
|
||||
n = n % (24 * 3600);
|
||||
hours = n / 3600;
|
||||
|
||||
n %= 3600;
|
||||
minutes = n / 60 ;
|
||||
|
||||
n %= 60;
|
||||
seconds = n;
|
||||
|
||||
return days & " " & "days "
|
||||
& hours & " " & "hours "
|
||||
& minutes & " " & "minutes "
|
||||
& seconds & " " & "seconds ");
|
||||
}
|
||||
}
|
||||
*/
|
||||
/**
|
||||
* Formats a JSON string with indents and new lines.
|
||||
* v1.0 by Ben Koshy (modified)
|
||||
*
|
||||
* @param str JSON string (Required)
|
||||
* @return Returns a string of indent-formated JSON
|
||||
* @author Ben Koshy (cf@animex.com)
|
||||
* @version 0, September 16, 2012
|
||||
*/
|
||||
// formatJson() :: formats and indents JSON string
|
||||
// based on blog post @ http://ketanjetty.com/coldfusion/javascript/format-json/
|
||||
// modified for CFScript By Ben Koshy @animexcom
|
||||
// usage: result = formatJson('STRING TO BE FORMATTED') OR result = formatJson(StringVariableToFormat);
|
||||
|
||||
// генерирует html разметку, чтобы не использовать <pre> и выровнять пробелы
|
||||
// содержит ошибку: делает перевод строки после запятой в строке в кавычках
|
||||
public string function formatJsonString(str) {
|
||||
var fjson = '';
|
||||
var pos = 0;
|
||||
var strLen = len(arguments.str);
|
||||
var indentStr = ' '; // Adjust Indent Token If you Like (замыкающий пробел - для выравнивания при пробелах после запятой)
|
||||
var newLine = '<br/>'; // Adjust New Line Token If you Like <BR>
|
||||
|
||||
for (var i=1; i<=strLen; i++) { //fix: <=
|
||||
var char = mid(arguments.str,i,1);
|
||||
|
||||
if (char == '}' || char == ']') {
|
||||
fjson &= newLine;
|
||||
pos = pos - 1;
|
||||
|
||||
for (var j=1; j <= pos; j++) {
|
||||
fjson &= indentStr;
|
||||
}
|
||||
}
|
||||
|
||||
fjson &= char;
|
||||
|
||||
if (char == '{' || char == '[' || char == ',') {
|
||||
fjson &= newLine;
|
||||
|
||||
if (char == '{' || char == '[') {
|
||||
pos = pos + 1;
|
||||
}
|
||||
|
||||
for (var k=1; k <= pos; k++) {
|
||||
fjson &= indentStr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fjson;
|
||||
}
|
||||
request.formatJsonString = formatJsonString;
|
||||
//нужна еще функция, которая сериализует структуру как pretty printed json. См. https://github.com/bennadel/JsonSerializer.cfc (все не совсем просто, например, не заранее не определен формат даты)
|
||||
</cfscript>
|
||||
|
||||
<cffunction name=structGetKey>
|
||||
<cfargument name="struct" type="struct"/>
|
||||
<cfargument name="key" type="string"/>
|
||||
<cfargument name="default" type="string" default=""/>
|
||||
|
||||
<cftry>
|
||||
<cfif StructKeyExists(ARGUMENTS.struct, ARGUMENTS.key)>
|
||||
<cfreturn structFind(ARGUMENTS.struct, ARGUMENTS.key)/>
|
||||
<cfelse>
|
||||
<cfreturn ARGUMENTS.default/>
|
||||
</cfif>
|
||||
<cfcatch type="any">
|
||||
<cfreturn ARGUMENTS.default/>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
<!--- можно проще - просто обработать исключение. вряд ли будет сильно хуже --->
|
||||
</cffunction>
|
||||
<cfset request.structGetKey = structGetKey/>
|
||||
|
||||
<cffunction name="setError">
|
||||
<cfargument name="container" type="struct"/>
|
||||
<cfargument name="message" type="string"/>
|
||||
|
||||
<cfset arguments.container.errorState=true/>
|
||||
<cfset arguments.container.errorMessage=arguments.message/>
|
||||
</cffunction>
|
||||
<cfset request.setError = setError/>
|
||||
|
||||
<cffunction name="snake2camel"
|
||||
access="public"
|
||||
returntype="any"
|
||||
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>
|
||||
<cfset request.snake2camel = snake2camel/>
|
||||
|
||||
<cffunction name="camel2snake"
|
||||
access="public"
|
||||
returntype="any"
|
||||
output="false"
|
||||
hint="convert camel style name to snake style name">
|
||||
<cfargument name="snake" type="string" required="true" />
|
||||
<cfreturn #reReplace(ARGUMENTS.snake,"([A-Z])","_\l\1","ALL")#/>
|
||||
</cffunction>
|
||||
<cfset request.camel2snake = camel2snake/>
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
<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>
|
||||
|
||||
|
||||
</ul>
|
||||
</cfoutput>
|
||||
<cfexit method="exittag"/>
|
||||
@@ -1,37 +0,0 @@
|
||||
<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"/>
|
||||
<!---
|
||||
---><layout:page section="header" pageInfo=#pageInfo#>
|
||||
|
||||
<layout:attribute name="title">
|
||||
<cfoutput><b>Отчет по PAYG</b> #request.auth.wz#</cfoutput>
|
||||
</layout:attribute>
|
||||
<layout:attribute name="controls">
|
||||
<!---skip filter link, filter is not implemented--->
|
||||
<!---<layout:language_switch/>--->
|
||||
</layout:attribute>
|
||||
</layout:page>
|
||||
|
||||
<!--- <script type="text/javascript"/>
|
||||
$(document).ready(function() {
|
||||
document.location="payg.cfm";
|
||||
});
|
||||
</script> --->
|
||||
|
||||
<h1>
|
||||
Подождите пожалуйста, формирование отчета может занять некоторое время
|
||||
</h1>
|
||||
<a href="payg.cfm">Если автоматического перенаправления не произошло, перейдите по ссылке</a>
|
||||
|
||||
|
||||
<layout:page section="footer"/>
|
||||
|
||||
<cflocation url="payg.cfm" addToken="No"/>
|
||||
|
||||
<!--- select * from s3billing.billing_per_user_fix_pl('2025-05-01 00:00:00','2025-06-01 00:00:00','1395'); --->
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
/*! jQuery v1.7.1 jquery.com | jquery.org/license */
|
||||
(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!ck[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){cl||(cl=c.createElement("iframe"),cl.frameBorder=cl.width=cl.height=0),b.appendChild(cl);if(!cm||!cl.createElement)cm=(cl.contentWindow||cl.contentDocument).document,cm.write((c.compatMode==="CSS1Compat"?"<!doctype html>":"")+"<html><body>"),cm.close();d=cm.createElement(a),cm.body.appendChild(d),e=f.css(d,"display"),b.removeChild(cl)}ck[a]=e}return ck[a]}function cu(a,b){var c={};f.each(cq.concat.apply([],cq.slice(0,b)),function(){c[this]=a});return c}function ct(){cr=b}function cs(){setTimeout(ct,0);return cr=f.now()}function cj(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ci(){try{return new a.XMLHttpRequest}catch(b){}}function cc(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g<i;g++){if(g===1)for(h in a.converters)typeof h=="string"&&(e[h.toLowerCase()]=a.converters[h]);l=k,k=d[g];if(k==="*")k=l;else if(l!=="*"&&l!==k){m=l+" "+k,n=e[m]||e["* "+k];if(!n){p=b;for(o in e){j=o.split(" ");if(j[0]===l||j[0]==="*"){p=e[j[1]+" "+k];if(p){o=e[o],o===!0?n=p:p===!0&&(n=o);break}}}}!n&&!p&&f.error("No conversion from "+m.replace(" "," to ")),n!==!0&&(c=n?n(c):p(o(c)))}}return c}function cb(a,c,d){var e=a.contents,f=a.dataTypes,g=a.responseFields,h,i,j,k;for(i in g)i in d&&(c[g[i]]=d[i]);while(f[0]==="*")f.shift(),h===b&&(h=a.mimeType||c.getResponseHeader("content-type"));if(h)for(i in e)if(e[i]&&e[i].test(h)){f.unshift(i);break}if(f[0]in d)j=f[0];else{for(i in d){if(!f[0]||a.converters[i+" "+f[0]]){j=i;break}k||(k=i)}j=j||k}if(j){j!==f[0]&&f.unshift(j);return d[j]}}function ca(a,b,c,d){if(f.isArray(b))f.each(b,function(b,e){c||bE.test(a)?d(a,e):ca(a+"["+(typeof e=="object"||f.isArray(e)?b:"")+"]",e,c,d)});else if(!c&&b!=null&&typeof b=="object")for(var e in b)ca(a+"["+e+"]",b[e],c,d);else d(a,b)}function b_(a,c){var d,e,g=f.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((g[d]?a:e||(e={}))[d]=c[d]);e&&f.extend(!0,a,e)}function b$(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h=a[f],i=0,j=h?h.length:0,k=a===bT,l;for(;i<j&&(k||!l);i++)l=h[i](c,d,e),typeof l=="string"&&(!k||g[l]?l=b:(c.dataTypes.unshift(l),l=b$(a,c,d,e,l,g)));(k||!l)&&!g["*"]&&(l=b$(a,c,d,e,"*",g));return l}function bZ(a){return function(b,c){typeof b!="string"&&(c=b,b="*");if(f.isFunction(c)){var d=b.toLowerCase().split(bP),e=0,g=d.length,h,i,j;for(;e<g;e++)h=d[e],j=/^\+/.test(h),j&&(h=h.substr(1)||"*"),i=a[h]=a[h]||[],i[j?"unshift":"push"](c)}}}function bC(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=b==="width"?bx:by,g=0,h=e.length;if(d>0){if(c!=="border")for(;g<h;g++)c||(d-=parseFloat(f.css(a,"padding"+e[g]))||0),c==="margin"?d+=parseFloat(f.css(a,c+e[g]))||0:d-=parseFloat(f.css(a,"border"+e[g]+"Width"))||0;return d+"px"}d=bz(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0;if(c)for(;g<h;g++)d+=parseFloat(f.css(a,"padding"+e[g]))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+e[g]+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+e[g]))||0);return d+"px"}function bp(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(bf,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bo(a){var b=c.createElement("div");bh.appendChild(b),b.innerHTML=a.outerHTML;return b.firstChild}function bn(a){var b=(a.nodeName||"").toLowerCase();b==="input"?bm(a):b!=="script"&&typeof a.getElementsByTagName!="undefined"&&f.grep(a.getElementsByTagName("input"),bm)}function bm(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bl(a){return typeof a.getElementsByTagName!="undefined"?a.getElementsByTagName("*"):typeof a.querySelectorAll!="undefined"?a.querySelectorAll("*"):[]}function bk(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bj(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c,d,e,g=f._data(a),h=f._data(b,g),i=g.events;if(i){delete h.handle,h.events={};for(c in i)for(d=0,e=i[c].length;d<e;d++)f.event.add(b,c+(i[c][d].namespace?".":"")+i[c][d].namespace,i[c][d],i[c][d].data)}h.data&&(h.data=f.extend({},h.data))}}function bi(a,b){return f.nodeName(a,"table")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function U(a){var b=V.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function T(a,b,c){b=b||0;if(f.isFunction(b))return f.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return f.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=f.grep(a,function(a){return a.nodeType===1});if(O.test(b))return f.filter(b,d,!c);b=f.filter(b,d)}return f.grep(a,function(a,d){return f.inArray(a,b)>=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?parseFloat(d):j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c<d;c++)b[a[c]]=!0;return b}var c=a.document,d=a.navigator,e=a.location,f=function(){function J(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(J,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.1",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j<k;j++)if((a=arguments[j])!=null)for(c in a){d=i[c],f=a[c];if(i===f)continue;l&&f&&(e.isPlainObject(f)||(g=e.isArray(f)))?(g?(g=!1,h=d&&e.isArray(d)?d:[]):h=d&&e.isPlainObject(d)?d:{},i[c]=e.extend(l,h,f)):f!==b&&(i[c]=f)}return i},e.extend({noConflict:function(b){a.$===e&&(a.$=g),b&&a.jQuery===e&&(a.jQuery=f);return e},isReady:!1,readyWait:1,holdReady:function(a){a?e.readyWait++:e.ready(!0)},ready:function(a){if(a===!0&&!--e.readyWait||a!==!0&&!e.isReady){if(!c.body)return setTimeout(e.ready,1);e.isReady=!0;if(a!==!0&&--e.readyWait>0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g<h;)if(c.apply(a[g++],d)===!1)break}else if(i){for(f in a)if(c.call(a[f],f,a[f])===!1)break}else for(;g<h;)if(c.call(a[g],g,a[g++])===!1)break;return a},trim:G?function(a){return a==null?"":G.call(a)}:function(a){return a==null?"":(a+"").replace(k,"").replace(l,"")},makeArray:function(a,b){var c=b||[];if(a!=null){var d=e.type(a);a.length==null||d==="string"||d==="function"||d==="regexp"||e.isWindow(a)?E.call(c,a):e.merge(c,a)}return c},inArray:function(a,b,c){var d;if(b){if(H)return H.call(b,a,c);d=b.length,c=c?c<0?Math.max(0,d+c):c:0;for(;c<d;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,c){var d=a.length,e=0;if(typeof c.length=="number")for(var f=c.length;e<f;e++)a[d++]=c[e];else while(c[e]!==b)a[d++]=c[e++];a.length=d;return a},grep:function(a,b,c){var d=[],e;c=!!c;for(var f=0,g=a.length;f<g;f++)e=!!b(a[f],f),c!==e&&d.push(a[f]);return d},map:function(a,c,d){var f,g,h=[],i=0,j=a.length,k=a instanceof e||j!==b&&typeof j=="number"&&(j>0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i<j;i++)f=c(a[i],i,d),f!=null&&(h[h.length]=f);else for(g in a)f=c(a[g],g,d),f!=null&&(h[h.length]=f);return h.concat.apply([],h)},guid:1,proxy:function(a,c){if(typeof c=="string"){var d=a[c];c=a,a=d}if(!e.isFunction(a))return b;var f=F.call(arguments,2),g=function(){return a.apply(c,f.concat(F.call(arguments)))};g.guid=a.guid=a.guid||g.guid||e.guid++;return g},access:function(a,c,d,f,g,h){var i=a.length;if(typeof c=="object"){for(var j in c)e.access(a,j,c[j],f,g,d);return a}if(d!==b){f=!h&&f&&e.isFunction(d);for(var k=0;k<i;k++)g(a[k],c,f?d.call(a[k],k,g(a[k],c)):d,h);return a}return i?g(a[0],c):b},now:function(){return(new Date).getTime()},uaMatch:function(a){a=a.toLowerCase();var b=r.exec(a)||s.exec(a)||t.exec(a)||a.indexOf("compatible")<0&&u.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}e.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function(d,f){f&&f instanceof e&&!(f instanceof a)&&(f=a(f));return e.fn.init.call(this,d,f,b)},a.fn.init.prototype=a.fn;var b=a(c);return a},browser:{}}),e.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){I["[object "+b+"]"]=b.toLowerCase()}),z=e.uaMatch(y),z.browser&&(e.browser[z.browser]=!0,e.browser.version=z.version),e.browser.webkit&&(e.browser.safari=!0),j.test(" ")&&(k=/^[\s\xA0]+/,l=/[\s\xA0]+$/),h=e(c),c.addEventListener?B=function(){c.removeEventListener("DOMContentLoaded",B,!1),e.ready()}:c.attachEvent&&(B=function(){c.readyState==="complete"&&(c.detachEvent("onreadystatechange",B),e.ready())});return e}(),g={};f.Callbacks=function(a){a=a?g[a]||h(a):{};var c=[],d=[],e,i,j,k,l,m=function(b){var d,e,g,h,i;for(d=0,e=b.length;d<e;d++)g=b[d],h=f.type(g),h==="array"?m(g):h==="function"&&(!a.unique||!o.has(g))&&c.push(g)},n=function(b,f){f=f||[],e=!a.memory||[b,f],i=!0,l=j||0,j=0,k=c.length;for(;c&&l<k;l++)if(c[l].apply(b,f)===!1&&a.stopOnFalse){e=!0;break}i=!1,c&&(a.once?e===!0?o.disable():c=[]:d&&d.length&&(e=d.shift(),o.fireWith(e[0],e[1])))},o={add:function(){if(c){var a=c.length;m(arguments),i?k=c.length:e&&e!==!0&&(j=a,n(e[0],e[1]))}return this},remove:function(){if(c){var b=arguments,d=0,e=b.length;for(;d<e;d++)for(var f=0;f<c.length;f++)if(b[d]===c[f]){i&&f<=k&&(k--,f<=l&&l--),c.splice(f--,1);if(a.unique)break}}return this},has:function(a){if(c){var b=0,d=c.length;for(;b<d;b++)if(a===c[b])return!0}return!1},empty:function(){c=[];return this},disable:function(){c=d=e=b;return this},disabled:function(){return!c},lock:function(){d=b,(!e||e===!0)&&o.disable();return this},locked:function(){return!d},fireWith:function(b,c){d&&(i?a.once||d.push([b,c]):(!a.once||!e)&&n(b,c));return this},fire:function(){o.fireWith(this,arguments);return this},fired:function(){return!!e}};return o};var i=[].slice;f.extend({Deferred:function(a){var b=f.Callbacks("once memory"),c=f.Callbacks("once memory"),d=f.Callbacks("memory"),e="pending",g={resolve:b,reject:c,notify:d},h={done:b.add,fail:c.add,progress:d.add,state:function(){return e},isResolved:b.fired,isRejected:c.fired,then:function(a,b,c){i.done(a).fail(b).progress(c);return this},always:function(){i.done.apply(i,arguments).fail.apply(i,arguments);return this},pipe:function(a,b,c){return f.Deferred(function(d){f.each({done:[a,"resolve"],fail:[b,"reject"],progress:[c,"notify"]},function(a,b){var c=b[0],e=b[1],g;f.isFunction(c)?i[a](function(){g=c.apply(this,arguments),g&&f.isFunction(g.promise)?g.promise().then(d.resolve,d.reject,d.notify):d[e+"With"](this===i?d:this,[g])}):i[a](d[e])})}).promise()},promise:function(a){if(a==null)a=h;else for(var b in h)a[b]=h[b];return a}},i=h.promise({}),j;for(j in g)i[j]=g[j].fire,i[j+"With"]=g[j].fireWith;i.done(function(){e="resolved"},c.disable,d.lock).fail(function(){e="rejected"},b.disable,d.lock),a&&a.call(i,i);return i},when:function(a){function m(a){return function(b){e[a]=arguments.length>1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c<d;c++)b[c]&&b[c].promise&&f.isFunction(b[c].promise)?b[c].promise().then(l(c),j.reject,m(c)):--g;g||j.resolveWith(j,b)}else j!==a&&j.resolveWith(j,d?[a]:[]);return k}}),f.support=function(){var b,d,e,g,h,i,j,k,l,m,n,o,p,q=c.createElement("div"),r=c.documentElement;q.setAttribute("className","t"),q.innerHTML=" <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>",d=q.getElementsByTagName("*"),e=q.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=q.getElementsByTagName("input")[0],b={leadingWhitespace:q.firstChild.nodeType===3,tbody:!q.getElementsByTagName("tbody").length,htmlSerialize:!!q.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:q.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete q.test}catch(s){b.deleteExpando=!1}!q.addEventListener&&q.attachEvent&&q.fireEvent&&(q.attachEvent("onclick",function(){b.noCloneEvent=!1}),q.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),q.appendChild(i),k=c.createDocumentFragment(),k.appendChild(q.lastChild),b.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,k.removeChild(i),k.appendChild(q),q.innerHTML="",a.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",q.style.width="2px",q.appendChild(j),b.reliableMarginRight=(parseInt((a.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0);if(q.attachEvent)for(o in{submit:1,change:1,focusin:1})n="on"+o,p=n in q,p||(q.setAttribute(n,"return;"),p=typeof q[n]=="function"),b[o+"Bubbles"]=p;k.removeChild(q),k=g=h=j=q=i=null,f(function(){var a,d,e,g,h,i,j,k,m,n,o,r=c.getElementsByTagName("body")[0];!r||(j=1,k="position:absolute;top:0;left:0;width:1px;height:1px;margin:0;",m="visibility:hidden;border:0;",n="style='"+k+"border:5px solid #000;padding:0;'",o="<div "+n+"><div></div></div>"+"<table "+n+" cellpadding='0' cellspacing='0'>"+"<tr><td></td></tr></table>",a=c.createElement("div"),a.style.cssText=m+"width:0;height:0;position:static;top:0;margin-top:"+j+"px",r.insertBefore(a,r.firstChild),q=c.createElement("div"),a.appendChild(q),q.innerHTML="<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>",l=q.getElementsByTagName("td"),p=l[0].offsetHeight===0,l[0].style.display="",l[1].style.display="none",b.reliableHiddenOffsets=p&&l[0].offsetHeight===0,q.innerHTML="",q.style.width=q.style.paddingLeft="1px",f.boxModel=b.boxModel=q.offsetWidth===2,typeof q.style.zoom!="undefined"&&(q.style.display="inline",q.style.zoom=1,b.inlineBlockNeedsLayout=q.offsetWidth===2,q.style.display="",q.innerHTML="<div style='width:4px;'></div>",b.shrinkWrapBlocks=q.offsetWidth!==2),q.style.cssText=k+m,q.innerHTML=o,d=q.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,i={doesNotAddBorder:e.offsetTop!==5,doesAddBorderForTableAndCells:h.offsetTop===5},e.style.position="fixed",e.style.top="20px",i.fixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",i.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,i.doesNotIncludeMarginInBodyOffset=r.offsetTop!==j,r.removeChild(a),q=a=null,f.extend(b,i))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e<g;e++)delete d[b[e]];if(!(c?m:f.isEmptyObject)(d))return}}if(!c){delete j[k].data;if(!m(j[k]))return}f.support.deleteExpando||!j.setInterval?delete j[k]:j[k]=null,i&&(f.support.deleteExpando?delete a[h]:a.removeAttribute?a.removeAttribute(h):a[h]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d,e,g,h=null;if(typeof a=="undefined"){if(this.length){h=f.data(this[0]);if(this[0].nodeType===1&&!f._data(this[0],"parsedAttrs")){e=this[0].attributes;for(var i=0,j=e.length;i<j;i++)g=e[i].name,g.indexOf("data-")===0&&(g=f.camelCase(g.substring(5)),l(this[0],g,h[g]));f._data(this[0],"parsedAttrs",!0)}}return h}if(typeof a=="object")return this.each(function(){f.data(this,a)});d=a.split("."),d[1]=d[1]?"."+d[1]:"";if(c===b){h=this.triggerHandler("getData"+d[1]+"!",[d[0]]),h===b&&this.length&&(h=f.data(this[0],a),h=l(this[0],a,h));return h===b&&d[1]?this.data(d[0]):h}return this.each(function(){var b=f(this),e=[d[0],c];b.triggerHandler("setData"+d[1]+"!",e),f.data(this,a,c),b.triggerHandler("changeData"+d[1]+"!",e)})},removeData:function(a){return this.each(function(){f.removeData(this,a)})}}),f.extend({_mark:function(a,b){a&&(b=(b||"fx")+"mark",f._data(a,b,(f._data(a,b)||0)+1))},_unmark:function(a,b,c){a!==!0&&(c=b,b=a,a=!1);if(b){c=c||"fx";var d=c+"mark",e=a?0:(f._data(b,d)||1)-1;e?f._data(b,d,e):(f.removeData(b,d,!0),n(b,c,"mark"))}},queue:function(a,b,c){var d;if(a){b=(b||"fx")+"queue",d=f._data(a,b),c&&(!d||f.isArray(c)?d=f._data(a,b,f.makeArray(c)):d.push(c));return d||[]}},dequeue:function(a,b){b=b||"fx";var c=f.queue(a,b),d=c.shift(),e={};d==="inprogress"&&(d=c.shift()),d&&(b==="fx"&&c.unshift("inprogress"),f._data(a,b+".run",e),d.call(a,function(){f.dequeue(a,b)},e)),c.length||(f.removeData(a,b+"queue "+b+".run",!0),n(a,b,"queue"))}}),f.fn.extend({queue:function(a,c){typeof a!="string"&&(c=a,a="fx");if(c===b)return f.queue(this[0],a);return this.each(function(){var b=f.queue(this,a,c);a==="fx"&&b[0]!=="inprogress"&&f.dequeue(this,a)})},dequeue:function(a){return this.each(function(){f.dequeue(this,a)})},delay:function(a,b){a=f.fx?f.fx.speeds[a]||a:a,b=b||"fx";return this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){function m(){--h||d.resolveWith(e,[e])}typeof a!="string"&&(c=a,a=b),a=a||"fx";var d=f.Deferred(),e=this,g=e.length,h=1,i=a+"defer",j=a+"queue",k=a+"mark",l;while(g--)if(l=f.data(e[g],i,b,!0)||(f.data(e[g],j,b,!0)||f.data(e[g],k,b,!0))&&f.data(e[g],i,f.Callbacks("once memory"),!0))h++,l.add(m);m();return d.promise()}});var o=/[\n\t\r]/g,p=/\s+/,q=/\r/g,r=/^(?:button|input)$/i,s=/^(?:button|input|object|select|textarea)$/i,t=/^a(?:rea)?$/i,u=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,v=f.support.getSetAttribute,w,x,y;f.fn.extend({attr:function(a,b){return f.access(this,a,b,!0,f.attr)},removeAttr:function(a){return this.each(function(){f.removeAttr(this,a)})},prop:function(a,b){return f.access(this,a,b,!0,f.prop)},removeProp:function(a){a=f.propFix[a]||a;return this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,g,h,i;if(f.isFunction(a))return this.each(function(b){f(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(p);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{g=" "+e.className+" ";for(h=0,i=b.length;h<i;h++)~g.indexOf(" "+b[h]+" ")||(g+=b[h]+" ");e.className=f.trim(g)}}}return this},removeClass:function(a){var c,d,e,g,h,i,j;if(f.isFunction(a))return this.each(function(b){f(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a=="string"||a===b){c=(a||"").split(p);for(d=0,e=this.length;d<e;d++){g=this[d];if(g.nodeType===1&&g.className)if(a){h=(" "+g.className+" ").replace(o," ");for(i=0,j=c.length;i<j;i++)h=h.replace(" "+c[i]+" "," ");g.className=f.trim(h)}else g.className=""}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";if(f.isFunction(a))return this.each(function(c){f(this).toggleClass(a.call(this,c,this.className,b),b)});return this.each(function(){if(c==="string"){var e,g=0,h=f(this),i=b,j=a.split(p);while(e=j[g++])i=d?i:!h.hasClass(e),h[i?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&f._data(this,"__className__",this.className),this.className=this.className||a===!1?"":f._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ",c=0,d=this.length;for(;c<d;c++)if(this[c].nodeType===1&&(" "+this[c].className+" ").replace(o," ").indexOf(b)>-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.nodeName.toLowerCase()]||f.valHooks[g.type];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c<d;c++){e=i[c];if(e.selected&&(f.support.optDisabled?!e.disabled:e.getAttribute("disabled")===null)&&(!e.parentNode.disabled||!f.nodeName(e.parentNode,"optgroup"))){b=f(e).val();if(j)return b;h.push(b)}}if(j&&!h.length&&i.length)return f(i[g]).val();return h},set:function(a,b){var c=f.makeArray(b);f(a).find("option").each(function(){this.selected=f.inArray(f(this).val(),c)>=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;h<g;h++)e=d[h],e&&(c=f.propFix[e]||e,f.attr(a,e,""),a.removeAttribute(v?e:c),u.test(e)&&c in a&&(a[c]=!1))}},attrHooks:{type:{set:function(a,b){if(r.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},value:{get:function(a,b){if(w&&f.nodeName(a,"button"))return w.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(w&&f.nodeName(a,"button"))return w.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e,g,h,i=a.nodeType;if(!!a&&i!==3&&i!==8&&i!==2){h=i!==1||!f.isXMLDoc(a),h&&(c=f.propFix[c]||c,g=f.propHooks[c]);return d!==b?g&&"set"in g&&(e=g.set(a,d,c))!==b?e:a[c]=d:g&&"get"in g&&(e=g.get(a,c))!==null?e:a[c]}},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):s.test(a.nodeName)||t.test(a.nodeName)&&a.href?0:b}}}}),f.attrHooks.tabindex=f.propHooks.tabIndex,x={get:function(a,c){var d,e=f.prop(a,c);return e===!0||typeof e!="boolean"&&(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},v||(y={name:!0,id:!0},w=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&(y[c]?d.nodeValue!=="":d.specified)?d.nodeValue:b},set:function(a,b,d){var e=a.getAttributeNode(d);e||(e=c.createAttribute(d),a.setAttributeNode(e));return e.nodeValue=b+""}},f.attrHooks.tabindex.set=w.set,f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})}),f.attrHooks.contenteditable={get:w.get,set:function(a,b,c){b===""&&(b="false"),w.set(a,b,c)}}),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex);return null}})),f.support.enctype||(f.propFix.enctype="encoding"),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/\bhover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function(a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")};
|
||||
f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k<c.length;k++){l=A.exec(c[k])||[],m=l[1],n=(l[2]||"").split(".").sort(),s=f.event.special[m]||{},m=(g?s.delegateType:s.bindType)||m,s=f.event.special[m]||{},o=f.extend({type:m,origType:l[1],data:e,handler:d,guid:d.guid,selector:g,quick:G(g),namespace:n.join(".")},p),r=j[m];if(!r){r=j[m]=[],r.delegateCount=0;if(!s.setup||s.setup.call(a,e,n,i)===!1)a.addEventListener?a.addEventListener(m,i,!1):a.attachEvent&&a.attachEvent("on"+m,i)}s.add&&(s.add.call(a,o),o.handler.guid||(o.handler.guid=d.guid)),g?r.splice(r.delegateCount++,0,o):r.push(o),f.event.global[m]=!0}a=null}},global:{},remove:function(a,b,c,d,e){var g=f.hasData(a)&&f._data(a),h,i,j,k,l,m,n,o,p,q,r,s;if(!!g&&!!(o=g.events)){b=f.trim(I(b||"")).split(" ");for(h=0;h<b.length;h++){i=A.exec(b[h])||[],j=k=i[1],l=i[2];if(!j){for(j in o)f.event.remove(a,j+b[h],c,d,!0);continue}p=f.event.special[j]||{},j=(d?p.delegateType:p.bindType)||j,r=o[j]||[],m=r.length,l=l?new RegExp("(^|\\.)"+l.split(".").sort().join("\\.(?:.*\\.)?")+"(\\.|$)"):null;for(n=0;n<r.length;n++)s=r[n],(e||k===s.origType)&&(!c||c.guid===s.guid)&&(!l||l.test(s.namespace))&&(!d||d===s.selector||d==="**"&&s.selector)&&(r.splice(n--,1),s.selector&&r.delegateCount--,p.remove&&p.remove.call(a,s));r.length===0&&m!==r.length&&((!p.teardown||p.teardown.call(a,l)===!1)&&f.removeEvent(a,j,g.handle),delete o[j])}f.isEmptyObject(o)&&(q=g.handle,q&&(q.elem=null),f.removeData(a,["events","handle"],!0))}},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,e,g){if(!e||e.nodeType!==3&&e.nodeType!==8){var h=c.type||c,i=[],j,k,l,m,n,o,p,q,r,s;if(E.test(h+f.event.triggered))return;h.indexOf("!")>=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;l<r.length&&!c.isPropagationStopped();l++)m=r[l][0],c.type=r[l][1],q=(f._data(m,"events")||{})[c.type]&&f._data(m,"handle"),q&&q.apply(m,d),q=o&&m[o],q&&f.acceptData(m)&&q.apply(m,d)===!1&&c.preventDefault();c.type=h,!g&&!c.isDefaultPrevented()&&(!p._default||p._default.apply(e.ownerDocument,d)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)&&o&&e[h]&&(h!=="focus"&&h!=="blur"||c.target.offsetWidth!==0)&&!f.isWindow(e)&&(n=e[o],n&&(e[o]=null),f.event.triggered=h,e[h](),f.event.triggered=b,n&&(e[o]=n));return c.result}},dispatch:function(c){c=f.event.fix(c||a.event);var d=(f._data(this,"events")||{})[c.type]||[],e=d.delegateCount,g=[].slice.call(arguments,0),h=!c.exclusive&&!c.namespace,i=[],j,k,l,m,n,o,p,q,r,s,t;g[0]=c,c.delegateTarget=this;if(e&&!c.target.disabled&&(!c.button||c.type!=="click")){m=f(this),m.context=this.ownerDocument||this;for(l=c.target;l!=this;l=l.parentNode||this){o={},q=[],m[0]=l;for(j=0;j<e;j++)r=d[j],s=r.selector,o[s]===b&&(o[s]=r.quick?H(l,r.quick):m.is(s)),o[s]&&q.push(r);q.length&&i.push({elem:l,matches:q})}}d.length>e&&i.push({elem:this,matches:d.slice(e)});for(j=0;j<i.length&&!c.isPropagationStopped();j++){p=i[j],c.currentTarget=p.elem;for(k=0;k<p.matches.length&&!c.isImmediatePropagationStopped();k++){r=p.matches[k];if(h||!c.namespace&&!r.namespace||c.namespace_re&&c.namespace_re.test(r.namespace))c.data=r.data,c.handleObj=r,n=((f.event.special[r.origType]||{}).handle||r.handler).apply(p.elem,g),n!==b&&(c.result=n,n===!1&&(c.preventDefault(),c.stopPropagation()))}}return c.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){a.which==null&&(a.which=b.charCode!=null?b.charCode:b.keyCode);return a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,d){var e,f,g,h=d.button,i=d.fromElement;a.pageX==null&&d.clientX!=null&&(e=a.target.ownerDocument||c,f=e.documentElement,g=e.body,a.pageX=d.clientX+(f&&f.scrollLeft||g&&g.scrollLeft||0)-(f&&f.clientLeft||g&&g.clientLeft||0),a.pageY=d.clientY+(f&&f.scrollTop||g&&g.scrollTop||0)-(f&&f.clientTop||g&&g.clientTop||0)),!a.relatedTarget&&i&&(a.relatedTarget=i===a.target?d.toElement:i),!a.which&&h!==b&&(a.which=h&1?1:h&2?3:h&4?2:0);return a}},fix:function(a){if(a[f.expando])return a;var d,e,g=a,h=f.event.fixHooks[a.type]||{},i=h.props?this.props.concat(h.props):this.props;a=f.Event(g);for(d=i.length;d;)e=i[--d],a[e]=g[e];a.target||(a.target=g.srcElement||c),a.target.nodeType===3&&(a.target=a.target.parentNode),a.metaKey===b&&(a.metaKey=a.ctrlKey);return h.filter?h.filter(a,g):a},special:{ready:{setup:f.bindReady},load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(a,b,c){f.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}},simulate:function(a,b,c,d){var e=f.extend(new f.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?f.event.trigger(e,null,b):f.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},f.event.handle=f.event.dispatch,f.removeEvent=c.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){a.detachEvent&&a.detachEvent("on"+b,c)},f.Event=function(a,b){if(!(this instanceof f.Event))return new f.Event(a,b);a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?K:J):this.type=a,b&&f.extend(this,b),this.timeStamp=a&&a.timeStamp||f.now(),this[f.expando]=!0},f.Event.prototype={preventDefault:function(){this.isDefaultPrevented=K;var a=this.originalEvent;!a||(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){this.isPropagationStopped=K;var a=this.originalEvent;!a||(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=K,this.stopPropagation()},isDefaultPrevented:J,isPropagationStopped:J,isImmediatePropagationStopped:J},f.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){f.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c=this,d=a.relatedTarget,e=a.handleObj,g=e.selector,h;if(!d||d!==c&&!f.contains(c,d))a.type=e.origType,h=e.handler.apply(this,arguments),a.type=b;return h}}}),f.support.submitBubbles||(f.event.special.submit={setup:function(){if(f.nodeName(this,"form"))return!1;f.event.add(this,"click._submit keypress._submit",function(a){var c=a.target,d=f.nodeName(c,"input")||f.nodeName(c,"button")?c.form:b;d&&!d._submit_attached&&(f.event.add(d,"submit._submit",function(a){this.parentNode&&!a.isTrigger&&f.event.simulate("submit",this.parentNode,a,!0)}),d._submit_attached=!0)})},teardown:function(){if(f.nodeName(this,"form"))return!1;f.event.remove(this,"._submit")}}),f.support.changeBubbles||(f.event.special.change={setup:function(){if(z.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")f.event.add(this,"propertychange._change",function(a){a.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),f.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1,f.event.simulate("change",this,a,!0))});return!1}f.event.add(this,"beforeactivate._change",function(a){var b=a.target;z.test(b.nodeName)&&!b._change_attached&&(f.event.add(b,"change._change",function(a){this.parentNode&&!a.isSimulated&&!a.isTrigger&&f.event.simulate("change",this.parentNode,a,!0)}),b._change_attached=!0)})},handle:function(a){var b=a.target;if(this!==b||a.isSimulated||a.isTrigger||b.type!=="radio"&&b.type!=="checkbox")return a.handleObj.handler.apply(this,arguments)},teardown:function(){f.event.remove(this,"._change");return z.test(this.nodeName)}}),f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){var d=0,e=function(a){f.event.simulate(b,a.target,f.event.fix(a),!0)};f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.fn.extend({on:function(a,c,d,e,g){var h,i;if(typeof a=="object"){typeof c!="string"&&(d=c,c=b);for(i in a)this.on(i,c,d,a[i],g);return this}d==null&&e==null?(e=c,d=c=b):e==null&&(typeof c=="string"?(e=d,d=b):(e=d,d=c,c=b));if(e===!1)e=J;else if(!e)return this;g===1&&(h=e,e=function(a){f().off(a);return h.apply(this,arguments)},e.guid=h.guid||(h.guid=f.guid++));return this.each(function(){f.event.add(this,a,e,d,c)})},one:function(a,b,c,d){return this.on.call(this,a,b,c,d,1)},off:function(a,c,d){if(a&&a.preventDefault&&a.handleObj){var e=a.handleObj;f(a.delegateTarget).off(e.namespace?e.type+"."+e.namespace:e.type,e.selector,e.handler);return this}if(typeof a=="object"){for(var g in a)this.off(g,c,a[g]);return this}if(c===!1||typeof c=="function")d=c,c=b;d===!1&&(d=J);return this.each(function(){f.event.remove(this,a,d,c)})},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},live:function(a,b,c){f(this.context).on(a,this.selector,b,c);return this},die:function(a,b){f(this.context).off(a,this.selector||"**",b);return this},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return arguments.length==1?this.off(a,"**"):this.off(b,a,c)},trigger:function(a,b){return this.each(function(){f.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return f.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||f.guid++,d=0,e=function(c){var e=(f._data(this,"lastToggle"+a.guid)||0)%d;f._data(this,"lastToggle"+a.guid,e+1),c.preventDefault();return b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),f.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){f.fn[b]=function(a,c){c==null&&(c=a,a=null);return arguments.length>0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}if(j.nodeType===1){g||(j[d]=c,j.sizset=h);if(typeof b!="string"){if(j===b){k=!0;break}}else if(m.filter(b,[j]).length>0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}j.nodeType===1&&!g&&(j[d]=c,j.sizset=h);if(j.nodeName.toLowerCase()===b){k=j;break}j=j[a]}e[h]=k}}}var a=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b<a.length;b++)a[b]===a[b-1]&&a.splice(b--,1)}return a},m.matches=function(a,b){return m(a,null,null,b)},m.matchesSelector=function(a,b){return m(b,null,null,[a]).length>0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e<f;e++){h=o.order[e];if(g=o.leftMatch[h].exec(a)){i=g[1],g.splice(1,1);if(i.substr(i.length-1)!=="\\"){g[1]=(g[1]||"").replace(j,""),d=o.find[h](g,b,c);if(d!=null){a=a.replace(o.match[h],"");break}}}}d||(d=typeof b.getElementsByTagName!="undefined"?b.getElementsByTagName("*"):[]);return{set:d,expr:a}},m.filter=function(a,c,d,e){var f,g,h,i,j,k,l,n,p,q=a,r=[],s=c,t=c&&c[0]&&m.isXML(c[0]);while(a&&c.length){for(h in o.filter)if((f=o.leftMatch[h].exec(a))!=null&&f[2]){k=o.filter[h],l=f[1],g=!1,f.splice(1,1);if(l.substr(l.length-1)==="\\")continue;s===r&&(r=[]);if(o.preFilter[h]){f=o.preFilter[h](f,s,d,r,e,t);if(!f)g=i=!0;else if(f===!0)continue}if(f)for(n=0;(j=s[n])!=null;n++)j&&(i=k(j,f,n,s),p=e^i,d&&i!=null?p?g=!0:s[n]=!1:p&&(r.push(j),g=!0));if(i!==b){d||(s=r),a=a.replace(o.match[h],"");if(!g)return[];break}}if(a===q)if(g==null)m.error(a);else break;q=a}return s},m.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)};var n=m.getText=function(a){var b,c,d=a.nodeType,e="";if(d){if(d===1||d===9){if(typeof a.textContent=="string")return a.textContent;if(typeof a.innerText=="string")return a.innerText.replace(k,"");for(a=a.firstChild;a;a=a.nextSibling)e+=n(a)}else if(d===3||d===4)return a.nodeValue}else for(b=0;c=a[b];b++)c.nodeType!==8&&(e+=n(c));return e},o=m.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(a){return a.getAttribute("href")},type:function(a){return a.getAttribute("type")}},relative:{"+":function(a,b){var c=typeof b=="string",d=c&&!l.test(b),e=c&&!d;d&&(b=b.toLowerCase());for(var f=0,g=a.length,h;f<g;f++)if(h=a[f]){while((h=h.previousSibling)&&h.nodeType!==1);a[f]=e||h&&h.nodeName.toLowerCase()===b?h||!1:h===b}e&&m.filter(b,a,!0)},">":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e<f;e++){c=a[e];if(c){var g=c.parentNode;a[e]=g.nodeName.toLowerCase()===b?g:!1}}}else{for(;e<f;e++)c=a[e],c&&(a[e]=d?c.parentNode:c.parentNode===b);d&&m.filter(b,a,!0)}},"":function(a,b,c){var d,f=e++,g=x;typeof b=="string"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g("parentNode",b,f,a,d,c)},"~":function(a,b,c){var d,f=e++,g=x;typeof b=="string"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g("previousSibling",b,f,a,d,c)}},find:{ID:function(a,b,c){if(typeof b.getElementById!="undefined"&&!c){var d=b.getElementById(a[1]);return d&&d.parentNode?[d]:[]}},NAME:function(a,b){if(typeof b.getElementsByName!="undefined"){var c=[],d=b.getElementsByName(a[1]);for(var e=0,f=d.length;e<f;e++)d[e].getAttribute("name")===a[1]&&c.push(d[e]);return c.length===0?null:c}},TAG:function(a,b){if(typeof b.getElementsByTagName!="undefined")return b.getElementsByTagName(a[1])}},preFilter:{CLASS:function(a,b,c,d,e,f){a=" "+a[1].replace(j,"")+" ";if(f)return a;for(var g=0,h;(h=b[g])!=null;g++)h&&(e^(h.className&&(" "+h.className+" ").replace(/[\t\n\r]/g," ").indexOf(a)>=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return b<c[3]-0},gt:function(a,b,c){return b>c[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h<i;h++)if(g[h]===a)return!1;return!0}m.error(e)},CHILD:function(a,b){var c,e,f,g,h,i,j,k=b[1],l=a;switch(k){case"only":case"first":while(l=l.previousSibling)if(l.nodeType===1)return!1;if(k==="first")return!0;l=a;case"last":while(l=l.nextSibling)if(l.nodeType===1)return!1;return!0;case"nth":c=b[2],e=b[3];if(c===1&&e===0)return!0;f=b[0],g=a.parentNode;if(g&&(g[d]!==f||!a.nodeIndex)){i=0;for(l=g.firstChild;l;l=l.nextSibling)l.nodeType===1&&(l.nodeIndex=++i);g[d]=f}j=a.nodeIndex-e;return c===0?j===0:j%c===0&&j/c>=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c<e;c++)d.push(a[c]);else for(;a[c];c++)d.push(a[c]);return d}}var u,v;c.documentElement.compareDocumentPosition?u=function(a,b){if(a===b){h=!0;return 0}if(!a.compareDocumentPosition||!b.compareDocumentPosition)return a.compareDocumentPosition?-1:1;return a.compareDocumentPosition(b)&4?-1:1}:(u=function(a,b){if(a===b){h=!0;return 0}if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],g=a.parentNode,i=b.parentNode,j=g;if(g===i)return v(a,b);if(!g)return-1;if(!i)return 1;while(j)e.unshift(j),j=j.parentNode;j=i;while(j)f.unshift(j),j=j.parentNode;c=e.length,d=f.length;for(var k=0;k<c&&k<d;k++)if(e[k]!==f[k])return v(e[k],f[k]);return k===c?v(a,f[k],-1):v(e[k],b,1)},v=function(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}),function(){var a=c.createElement("div"),d="script"+(new Date).getTime(),e=c.documentElement;a.innerHTML="<a name='"+d+"'/>",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="<p class='TEST'></p>";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="<div class='test e'></div><div class='test'></div>";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h<i;h++)m(a,g[h],e,c);return m.filter(f,e)};m.attr=f.attr,m.selectors.attrMap={},f.find=m,f.expr=m.selectors,f.expr[":"]=f.expr.filters,f.unique=m.uniqueSort,f.text=m.getText,f.isXMLDoc=m.isXML,f.contains=m.contains}();var L=/Until$/,M=/^(?:parents|prevUntil|prevAll)/,N=/,/,O=/^.[^:#\[\.,]*$/,P=Array.prototype.slice,Q=f.expr.match.POS,R={children:!0,contents:!0,next:!0,prev:!0};f.fn.extend({find:function(a){var b=this,c,d;if(typeof a!="string")return f(a).filter(function(){for(c=0,d=b.length;c<d;c++)if(f.contains(b[c],this))return!0});var e=this.pushStack("","find",a),g,h,i;for(c=0,d=this.length;c<d;c++){g=e.length,f.find(a,this[c],e);if(c>0)for(h=g;h<e.length;h++)for(i=0;i<g;i++)if(e[i]===e[h]){e.splice(h--,1);break}}return e},has:function(a){var b=f(a);return this.filter(function(){for(var a=0,c=b.length;a<c;a++)if(f.contains(this,b[a]))return!0})},not:function(a){return this.pushStack(T(this,a,!1),"not",a)},filter:function(a){return this.pushStack(T(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?Q.test(a)?f(a,this.context).index(this[0])>=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d<a.length;d++)f(g).is(a[d])&&c.push({selector:a[d],elem:g,level:h});g=g.parentNode,h++}return c}var i=Q.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d<e;d++){g=this[d];while(g){if(i?i.index(g)>-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/<tbody/i,_=/<|&#?\w+;/,ba=/<(?:script|style)/i,bb=/<(?:script|object|embed|option|style)/i,bc=new RegExp("<(?:"+V+")","i"),bd=/checked\s*(?:[^=]|=\s*.checked.)/i,be=/\/(java|ecma)script/i,bf=/^\s*<!(?:\[CDATA\[|\-\-)/,bg={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div<div>","</div>"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function()
|
||||
{for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1></$2>");try{for(var c=0,d=this.length;c<d;c++)this[c].nodeType===1&&(f.cleanData(this[c].getElementsByTagName("*")),this[c].innerHTML=a)}catch(e){this.empty().append(a)}}else f.isFunction(a)?this.each(function(b){var c=f(this);c.html(a.call(this,b,c.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(f.isFunction(a))return this.each(function(b){var c=f(this),d=c.html();c.replaceWith(a.call(this,b,d))});typeof a!="string"&&(a=f(a).detach());return this.each(function(){var b=this.nextSibling,c=this.parentNode;f(this).remove(),b?f(b).before(a):f(c).append(a)})}return this.length?this.pushStack(f(f.isFunction(a)?a():a),"replaceWith",a):this},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){var e,g,h,i,j=a[0],k=[];if(!f.support.checkClone&&arguments.length===3&&typeof j=="string"&&bd.test(j))return this.each(function(){f(this).domManip(a,c,d,!0)});if(f.isFunction(j))return this.each(function(e){var g=f(this);a[0]=j.call(this,e,c?g.html():b),g.domManip(a,c,d)});if(this[0]){i=j&&j.parentNode,f.support.parentNode&&i&&i.nodeType===11&&i.childNodes.length===this.length?e={fragment:i}:e=f.buildFragment(a,this,k),h=e.fragment,h.childNodes.length===1?g=h=h.firstChild:g=h.firstChild;if(g){c=c&&f.nodeName(g,"tr");for(var l=0,m=this.length,n=m-1;l<m;l++)d.call(c?bi(this[l],g):this[l],e.cacheable||m>1&&l<n?f.clone(h,!0,!0):h)}k.length&&f.each(k,bp)}return this}}),f.buildFragment=function(a,b,d){var e,g,h,i,j=a[0];b&&b[0]&&(i=b[0].ownerDocument||b[0]),i.createDocumentFragment||(i=c),a.length===1&&typeof j=="string"&&j.length<512&&i===c&&j.charAt(0)==="<"&&!bb.test(j)&&(f.support.checkClone||!bd.test(j))&&(f.support.html5Clone||!bc.test(j))&&(g=!0,h=f.fragments[j],h&&h!==1&&(e=h)),e||(e=i.createDocumentFragment(),f.clean(a,i,e,d)),g&&(f.fragments[j]=h?e:1);return{fragment:e,cacheable:g}},f.fragments={},f.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){f.fn[a]=function(c){var d=[],e=f(c),g=this.length===1&&this[0].parentNode;if(g&&g.nodeType===11&&g.childNodes.length===1&&e.length===1){e[b](this[0]);return this}for(var h=0,i=e.length;h<i;h++){var j=(h>0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||!bc.test("<"+a.nodeName)?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1></$2>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");b===c?bh.appendChild(o):U(b).appendChild(o),o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]==="<table>"&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i<r;i++)bn(k[i]);else bn(k);k.nodeType?h.push(k):h=f.merge(h,k)}if(d){g=function(a){return!a.type||be.test(a.type)};for(j=0;h[j];j++)if(e&&f.nodeName(h[j],"script")&&(!h[j].type||h[j].type.toLowerCase()==="text/javascript"))e.push(h[j].parentNode?h[j].parentNode.removeChild(h[j]):h[j]);else{if(h[j].nodeType===1){var s=f.grep(h[j].getElementsByTagName("script"),g);h.splice.apply(h,[j+1,0].concat(s))}d.appendChild(h[j])}}return h},cleanData:function(a){var b,c,d=f.cache,e=f.event.special,g=f.support.deleteExpando;for(var h=0,i;(i=a[h])!=null;h++){if(i.nodeName&&f.noData[i.nodeName.toLowerCase()])continue;c=i[f.expando];if(c){b=d[c];if(b&&b.events){for(var j in b.events)e[j]?f.event.remove(i,j):f.removeEvent(i,j,b.handle);b.handle&&(b.handle.elem=null)}g?delete i[f.expando]:i.removeAttribute&&i.removeAttribute(f.expando),delete d[c]}}}});var bq=/alpha\([^)]*\)/i,br=/opacity=([^)]*)/,bs=/([A-Z]|^ms)/g,bt=/^-?\d+(?:px)?$/i,bu=/^-?\d/,bv=/^([\-+])=([\-+.\de]+)/,bw={position:"absolute",visibility:"hidden",display:"block"},bx=["Left","Right"],by=["Top","Bottom"],bz,bA,bB;f.fn.css=function(a,c){if(arguments.length===2&&c===b)return this;return f.access(this,a,c,!0,function(a,c,d){return d!==b?f.style(a,c,d):f.css(a,c)})},f.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bz(a,"opacity","opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":f.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!!a&&a.nodeType!==3&&a.nodeType!==8&&!!a.style){var g,h,i=f.camelCase(c),j=a.style,k=f.cssHooks[i];c=f.cssProps[i]||i;if(d===b){if(k&&"get"in k&&(g=k.get(a,!1,e))!==b)return g;return j[c]}h=typeof d,h==="string"&&(g=bv.exec(d))&&(d=+(g[1]+1)*+g[2]+parseFloat(f.css(a,c)),h="number");if(d==null||h==="number"&&isNaN(d))return;h==="number"&&!f.cssNumber[i]&&(d+="px");if(!k||!("set"in k)||(d=k.set(a,d))!==b)try{j[c]=d}catch(l){}}},css:function(a,c,d){var e,g;c=f.camelCase(c),g=f.cssHooks[c],c=f.cssProps[c]||c,c==="cssFloat"&&(c="float");if(g&&"get"in g&&(e=g.get(a,!0,d))!==b)return e;if(bz)return bz(a,c)},swap:function(a,b,c){var d={};for(var e in b)d[e]=a.style[e],a.style[e]=b[e];c.call(a);for(e in b)a.style[e]=d[e]}}),f.curCSS=f.css,f.each(["height","width"],function(a,b){f.cssHooks[b]={get:function(a,c,d){var e;if(c){if(a.offsetWidth!==0)return bC(a,b,d);f.swap(a,bw,function(){e=bC(a,b,d)});return e}},set:function(a,b){if(!bt.test(b))return b;b=parseFloat(b);if(b>=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return br.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bq,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bq.test(g)?g.replace(bq,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bz(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,b){var c,d,e;b=b.replace(bs,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b)));return c}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f===null&&g&&(e=g[b])&&(f=e),!bt.test(f)&&bu.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f||0,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bD=/%20/g,bE=/\[\]$/,bF=/\r?\n/g,bG=/#.*$/,bH=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bI=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bJ=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bK=/^(?:GET|HEAD)$/,bL=/^\/\//,bM=/\?/,bN=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bO=/^(?:select|textarea)/i,bP=/\s+/,bQ=/([?&])_=[^&]*/,bR=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bS=f.fn.load,bT={},bU={},bV,bW,bX=["*/"]+["*"];try{bV=e.href}catch(bY){bV=c.createElement("a"),bV.href="",bV=bV.href}bW=bR.exec(bV.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bS)return bS.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("<div>").append(c.replace(bN,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bO.test(this.nodeName)||bI.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bF,"\r\n")}}):{name:b.name,value:c.replace(bF,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b_(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b_(a,b);return a},ajaxSettings:{url:bV,isLocal:bJ.test(bW[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bX},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bZ(bT),ajaxTransport:bZ(bU),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?cb(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cc(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bH.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bG,"").replace(bL,bW[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bP),d.crossDomain==null&&(r=bR.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bW[1]&&r[2]==bW[2]&&(r[3]||(r[1]==="http:"?80:443))==(bW[3]||(bW[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),b$(bT,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bK.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bM.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bQ,"$1_="+x);d.url=y+(y===d.url?(bM.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bX+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bU,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)ca(g,a[g],c,e);return d.join("&").replace(bD,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cd=f.now(),ce=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cd++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ce.test(b.url)||e&&ce.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ce,l),b.url===j&&(e&&(k=k.replace(ce,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cf=a.ActiveXObject?function(){for(var a in ch)ch[a](0,1)}:!1,cg=0,ch;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ci()||cj()}:ci,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cf&&delete ch[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cg,cf&&(ch||(ch={},f(a).unload(cf)),ch[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var ck={},cl,cm,cn=/^(?:toggle|show|hide)$/,co=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cp,cq=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cr;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu("show",3),a,b,c);for(var g=0,h=this.length;g<h;g++)d=this[g],d.style&&(e=d.style.display,!f._data(d,"olddisplay")&&e==="none"&&(e=d.style.display=""),e===""&&f.css(d,"display")==="none"&&f._data(d,"olddisplay",cv(d.nodeName)));for(g=0;g<h;g++){d=this[g];if(d.style){e=d.style.display;if(e===""||e==="none")d.style.display=f._data(d,"olddisplay")||""}}return this},hide:function(a,b,c){if(a||a===0)return this.animate(cu("hide",3),a,b,c);var d,e,g=0,h=this.length;for(;g<h;g++)d=this[g],d.style&&(e=f.css(d,"display"),e!=="none"&&!f._data(d,"olddisplay")&&f._data(d,"olddisplay",e));for(g=0;g<h;g++)this[g].style&&(this[g].style.display="none");return this},_toggle:f.fn.toggle,toggle:function(a,b,c){var d=typeof a=="boolean";f.isFunction(a)&&f.isFunction(b)?this._toggle.apply(this,arguments):a==null||d?this.each(function(){var b=d?a:f(this).is(":hidden");f(this)[b?"show":"hide"]()}):this.animate(cu("toggle",3),a,b,c);return this},fadeTo:function(a,b,c,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){function g(){e.queue===!1&&f._mark(this);var b=f.extend({},e),c=this.nodeType===1,d=c&&f(this).is(":hidden"),g,h,i,j,k,l,m,n,o;b.animatedProperties={};for(i in a){g=f.camelCase(i),i!==g&&(a[g]=a[i],delete a[i]),h=a[g],f.isArray(h)?(b.animatedProperties[g]=h[1],h=a[g]=h[0]):b.animatedProperties[g]=b.specialEasing&&b.specialEasing[g]||b.easing||"swing";if(h==="hide"&&d||h==="show"&&!d)return b.complete.call(this);c&&(g==="height"||g==="width")&&(b.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY],f.css(this,"display")==="inline"&&f.css(this,"float")==="none"&&(!f.support.inlineBlockNeedsLayout||cv(this.nodeName)==="inline"?this.style.display="inline-block":this.style.zoom=1))}b.overflow!=null&&(this.style.overflow="hidden");for(i in a)j=new f.fx(this,b,i),h=a[i],cn.test(h)?(o=f._data(this,"toggle"+i)||(h==="toggle"?d?"show":"hide":0),o?(f._data(this,"toggle"+i,o==="show"?"hide":"show"),j[o]()):j[h]()):(k=co.exec(h),l=j.cur(),k?(m=parseFloat(k[2]),n=k[3]||(f.cssNumber[i]?"":"px"),n!=="px"&&(f.style(this,i,(m||1)+n),l=(m||1)/j.cur()*l,f.style(this,i,l+n)),k[1]&&(m=(k[1]==="-="?-1:1)*m+l),j.custom(l,m,n)):j.custom(l,h,""));return!0}var e=f.speed(b,c,d);if(f.isEmptyObject(a))return this.each(e.complete,[!1]);a=f.extend({},a);return e.queue===!1?this.each(g):this.queue(e.queue,g)},stop:function(a,c,d){typeof a!="string"&&(d=c,c=a,a=b),c&&a!==!1&&this.queue(a||"fx",[]);return this.each(function(){function h(a,b,c){var e=b[c];f.removeData(a,c,!0),e.stop(d)}var b,c=!1,e=f.timers,g=f._data(this);d||f._unmark(!0,this);if(a==null)for(b in g)g[b]&&g[b].stop&&b.indexOf(".run")===b.length-4&&h(this,g,b);else g[b=a+".run"]&&g[b].stop&&h(this,g,b);for(b=e.length;b--;)e[b].elem===this&&(a==null||e[b].queue===a)&&(d?e[b](!0):e[b].saveState(),c=!0,e.splice(b,1));(!d||!c)&&f.dequeue(this,a)})}}),f.each({slideDown:cu("show",1),slideUp:cu("hide",1),slideToggle:cu("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){f.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),f.extend({speed:function(a,b,c){var d=a&&typeof a=="object"?f.extend({},a):{complete:c||!c&&b||f.isFunction(a)&&a,duration:a,easing:c&&b||b&&!f.isFunction(b)&&b};d.duration=f.fx.off?0:typeof d.duration=="number"?d.duration:d.duration in f.fx.speeds?f.fx.speeds[d.duration]:f.fx.speeds._default;if(d.queue==null||d.queue===!0)d.queue="fx";d.old=d.complete,d.complete=function(a){f.isFunction(d.old)&&d.old.call(this),d.queue?f.dequeue(this,d.queue):a!==!1&&f._unmark(this)};return d},easing:{linear:function(a,b,c,d){return c+d*a},swing:function(a,b,c,d){return(-Math.cos(a*Math.PI)/2+.5)*d+c}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig=b.orig||{}}}),f.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(f.fx.step[this.prop]||f.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a,b=f.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b==="auto"?0:b:a},custom:function(a,c,d){function h(a){return e.step(a)}var e=this,g=f.fx;this.startTime=cr||cs(),this.end=c,this.now=this.start=a,this.pos=this.state=0,this.unit=d||this.unit||(f.cssNumber[this.prop]?"":"px"),h.queue=this.options.queue,h.elem=this.elem,h.saveState=function(){e.options.hide&&f._data(e.elem,"fxshow"+e.prop)===b&&f._data(e.elem,"fxshow"+e.prop,e.start)},h()&&f.timers.push(h)&&!cp&&(cp=setInterval(g.tick,g.interval))},show:function(){var a=f._data(this.elem,"fxshow"+this.prop);this.options.orig[this.prop]=a||f.style(this.elem,this.prop),this.options.show=!0,a!==b?this.custom(this.cur(),a):this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur()),f(this.elem).show()},hide:function(){this.options.orig[this.prop]=f._data(this.elem,"fxshow"+this.prop)||f.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b,c,d,e=cr||cs(),g=!0,h=this.elem,i=this.options;if(a||e>=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c<b.length;c++)a=b[c],!a()&&b[c]===a&&b.splice(c--,1);b.length||f.fx.stop()},interval:13,stop:function(){clearInterval(cp),cp=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){f.style(a.elem,"opacity",a.now)},_default:function(a){a.elem.style&&a.elem.style[a.prop]!=null?a.elem.style[a.prop]=a.now+a.unit:a.elem[a.prop]=a.now}}}),f.each(["width","height"],function(a,b){f.fx.step[b]=function(a){f.style(a.elem,b,Math.max(0,a.now)+a.unit)}}),f.expr&&f.expr.filters&&(f.expr.filters.animated=function(a){return f.grep(f.timers,function(b){return a===b.elem}).length});var cw=/^t(?:able|d|h)$/i,cx=/^(?:body|html)$/i;"getBoundingClientRect"in c.documentElement?f.fn.offset=function(a){var b=this[0],c;if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);try{c=b.getBoundingClientRect()}catch(d){}var e=b.ownerDocument,g=e.documentElement;if(!c||!f.contains(g,b))return c?{top:c.top,left:c.left}:{top:0,left:0};var h=e.body,i=cy(e),j=g.clientTop||h.clientTop||0,k=g.clientLeft||h.clientLeft||0,l=i.pageYOffset||f.support.boxModel&&g.scrollTop||h.scrollTop,m=i.pageXOffset||f.support.boxModel&&g.scrollLeft||h.scrollLeft,n=c.top+l-j,o=c.left+m-k;return{top:n,left:o}}:f.fn.offset=function(a){var b=this[0];if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);var c,d=b.offsetParent,e=b,g=b.ownerDocument,h=g.documentElement,i=g.body,j=g.defaultView,k=j?j.getComputedStyle(b,null):b.currentStyle,l=b.offsetTop,m=b.offsetLeft;while((b=b.parentNode)&&b!==i&&b!==h){if(f.support.fixedPosition&&k.position==="fixed")break;c=j?j.getComputedStyle(b,null):b.currentStyle,l-=b.scrollTop,m-=b.scrollLeft,b===d&&(l+=b.offsetTop,m+=b.offsetLeft,f.support.doesNotAddBorder&&(!f.support.doesAddBorderForTableAndCells||!cw.test(b.nodeName))&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),e=d,d=b.offsetParent),f.support.subtractsBorderForOverflowNotVisible&&c.overflow!=="visible"&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),k=c}if(k.position==="relative"||k.position==="static")l+=i.offsetTop,m+=i.offsetLeft;f.support.fixedPosition&&k.position==="fixed"&&(l+=Math.max(h.scrollTop,i.scrollTop),m+=Math.max(h.scrollLeft,i.scrollLeft));return{top:l,left:m}},f.offset={bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.support.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,d,"padding")):this[d]():null},f.fn["outer"+c]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,d,a?"margin":"border")):this[d]():null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNumeric(j)?j:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window);
|
||||
@@ -1,3 +0,0 @@
|
||||
/* JQuery Searchable DropDown Plugin | Copyright (c) 2012 xhaggi */
|
||||
/*modidfed 14.11.2016|18.01.2018 by msyu - display:inline-block, padding-top: 0 for chrome; BUG: maxListSize IS IGNORED, use instead maxMultiMatch; chrome highlighted position correction;*/
|
||||
(function($){var B=register("searchable");B.defaults={maxListSize:100,maxMultiMatch:50,exactMatch:false,wildcards:true,ignoreCase:true,warnMultiMatch:"top {0} matches ...",warnNoMatch:"no matches ...",latency:200,zIndex:"auto"};B.execute=function(g,h){var j=null;var k=null;var l=null;if($.browser.msie&&parseInt(jQuery.browser.version)<7)return this;if(this.nodeName!="SELECT"||this.size>1)return this;var m=$(this);var n={index:-1,options:null};var o="lang";var p=false;$.browser.chrome=/chrome/.test(navigator.userAgent.toLowerCase());if($.browser.chrome)$.browser.safari=false;if($.meta){g=$.extend({},options,m.data())}var q=$("<div/>");var r=$("<div/>");var t=$("<input/>");var u=$("<select/>");var x=$("<option>"+g.warnMultiMatch.replace(/\{0\}/g,g.maxMultiMatch)+"</option>").attr("disabled","true");var y=$("<option>"+g.warnNoMatch+"</option>").attr("disabled","true");var z={option:function(a){return $(u.get(0).options[a])},selected:function(){return u.find(":selected")},selectedIndex:function(a){if(a>-1)u.get(0).selectedIndex=a;return u.get(0).selectedIndex},size:function(a){u.attr("size",Math.max(2,Math.min(a,20)))},reset:function(){if((m.get(0).selectedIndex-1)==m.data("index"))return;var a=m.get(0).selectedIndex;var b=m.get(0).length;var c=Math.floor(g.maxMultiMatch/2);var d=Math.max(1,(a-c));var e=Math.min(b,Math.max(g.maxMultiMatch,(a+c)));var f=a-d;u.empty();this.size(e-d);for(var i=d;i<e;i++)u.append($(m.get(0).options[i]).clone().attr(o,i-1));if(e>g.maxMultiMatch)u.append(x);u.get(0).selectedIndex=f}};draw();var A=false;r.mouseover(function(){A=true});r.mouseout(function(){A=false});u.mouseover(function(){A=true});u.mouseout(function(){A=false});t.click(function(e){if(!p)enable(e,true);else disable(e,true)});t.blur(function(e){if(!A&&p)disable(e,true)});m.keydown(function(e){if(e.keyCode!=9&&!e.shiftKey&&!e.ctrlKey&&!e.altKey)t.click()});m.click(function(e){u.focus()});u.click(function(e){if(z.selectedIndex()<0)return;disable(e)});u.focus(function(e){t.focus()});u.blur(function(e){if(!A)disable(e,true)});u.mousemove(function(e){if($.browser.opera&&parseFloat(jQuery.browser.version)>=9.8)return true;var a=Math.floor(parseFloat(/([0-9\.]+)px/.exec(z.option(0).css("font-size"))));var b=4;if($.browser.opera)b=2.5;if($.browser.safari)b=3;if($.browser.chrome)b=3.4;a+=a/b;z.selectedIndex(Math.floor((e.pageY-u.offset().top+this.scrollTop)/a))});r.click(function(e){t.click()});t.keyup(function(e){if(jQuery.inArray(e.keyCode,new Array(9,13,16,33,34,35,36,38,40))>-1)return true;l=$.trim(t.val().toLowerCase());clearSearchTimer();j=setTimeout(searching,g.latency)});t.keydown(function(e){if(e.keyCode==9){disable(e)}if(e.shiftKey||e.ctrlKey||e.altKey)return;switch(e.keyCode){case 13:disable(e);m.focus();break;case 27:disable(e,true);m.focus();break;case 33:if(z.selectedIndex()-u.attr("size")>0){z.selectedIndex(z.selectedIndex()-u.attr("size"))}else{z.selectedIndex(0)}synchronize();break;case 34:if(z.selectedIndex()+u.attr("size")<u.get(0).options.length-1){z.selectedIndex(z.selectedIndex()+u.attr("size"))}else{z.selectedIndex(u.get(0).options.length-1)}synchronize();break;case 38:if(z.selectedIndex()>0){z.selectedIndex(z.selectedIndex()-1);synchronize()}break;case 40:if(z.selectedIndex()<u.get(0).options.length-1){z.selectedIndex(z.selectedIndex()+1);synchronize()}break;default:return true}return false});function draw(){m.css("text-decoration","none");m.width(m.outerWidth());m.height(m.outerHeight());q.css("position","relative");/*msyu*/q.css("display","inline-block");q.css("margin","0");/*/msyu*/q.css("width",m.outerWidth());if($.browser.msie)q.css("z-index",h);r.css({"position":"absolute","top":0,"left":0,"width":m.outerWidth(),"height":m.outerHeight(),/*msyu*/"background-color":"#BBEE55","opacity":"0.2"/*/msyu*/});t.attr("type","text");t.hide();t.height(m.outerHeight());t.css({"position":"absolute","top":0,"left":0,"margin":"0px","padding":"0px","outline-style":"none","border-style":"solid","border-bottom-style":"none","border-color":"transparent","background-color":"transparent"});var a=new Array();a.push("border-left-width");a.push("border-top-width");a.push("font-size");a.push("font-stretch");a.push("font-variant");a.push("font-weight");a.push("color");a.push("text-align");a.push("text-indent");a.push("text-shadow");a.push("text-transform");a.push("padding-left");a.push("padding-top");for(var i=0;i<a.length;i++)t.css(a[i],m.css(a[i]));if($.browser.msie&&parseInt(jQuery.browser.version)<8){t.css("padding","0px");t.css("padding-left","3px");t.css("border-left-width","2px");t.css("border-top-width","3px")}else if($.browser.chrome){t.height(m.innerHeight());t.css("text-transform","none");t.css("padding-left",parseFloatPx(t.css("padding-left"))+3);t.css("padding-top",/*2*/0)}else if($.browser.safari){t.height(m.innerHeight());t.css("padding-top",2);t.css("padding-left",3);t.css("text-transform","none")}else if($.browser.opera){t.height(m.innerHeight());var b=parseFloatPx(m.css("padding-left"));t.css("padding-left",b==1?b+1:b);t.css("padding-top",0)}else if($.browser.mozilla){t.css("padding-top","0px");t.css("border-top","0px");t.css("padding-left",parseFloatPx(m.css("padding-left"))+3)}else{t.css("padding-left",parseFloatPx(m.css("padding-left"))+3);t.css("padding-top",parseFloatPx(m.css("padding-top"))+1)}var c=parseFloatPx(m.css("padding-left"))+parseFloatPx(m.css("padding-right"))+parseFloatPx(m.css("border-left-width"))+parseFloatPx(m.css("border-left-width"))+23;t.width(m.outerWidth()-c);var w=m.css("width");var d=m.outerWidth();m.css("width","auto");d=d>m.outerWidth()?d:m.outerWidth();m.css("width",w);u.hide();z.size(m.get(0).length);u.css({"position":"absolute","top":m.outerHeight(),"left":0,"width":d,"border":"1px solid #333","font-weight":"normal","padding":0,"background-color":m.css("background-color"),"text-transform":m.css("text-transform")});var e=/^\d+$/.test(m.css("z-index"))?m.css("z-index"):1;if(g.zIndex&&/^\d+$/.test(g.zIndex))e=g.zIndex;r.css("z-index",(e).toString(10));t.css("z-index",(e+1).toString(10));u.css("z-index",(e+2).toString(10));m.wrap(q);m.after(r);m.after(t);m.after(u)};function enable(e,s,v){if(m.attr("disabled"))return false;m.prepend("<option />");if(typeof v=="undefined")p=!p;z.reset();synchronize();store();if(s)u.show();t.show();t.focus();t.select();m.get(0).selectedIndex=0;if(typeof e!="undefined")e.stopPropagation()};function disable(e,a){p=false;m.find(":first").remove();clearSearchTimer();t.hide();u.hide();if(typeof a!="undefined")restore();populate();if(typeof e!="undefined")e.stopPropagation()};function clearSearchTimer(){if(j!=null)clearTimeout(j)};function populate(){if(z.selectedIndex()<0||z.selected().get(0).disabled)return;m.get(0).selectedIndex=parseInt(u.find(":selected").attr(o));m.change();m.data("index",new Number(m.get(0).selectedIndex))};function synchronize(){if(z.selectedIndex()>-1&&!z.selected().get(0).disabled)t.val(u.find(":selected").text());else t.val(m.find(":selected").text())};function store(){n.index=z.selectedIndex();n.options=new Array();for(var i=0;i<u.get(0).options.length;i++)n.options.push(u.get(0).options[i])};function restore(){u.empty();for(var i=0;i<n.options.length;i++)u.append(n.options[i]);z.selectedIndex(n.index);z.size(n.options.length)};function escapeRegExp(a){var b=["/",".","*","+","?","|","(",")","[","]","{","}","\\","^","$"];var c=new RegExp("(\\"+b.join("|\\")+")","g");return a.replace(c,"\\$1")};function searching(){if(k==l){j=null;return}var a=0;k=l;u.hide();u.empty();var b=escapeRegExp(l);if(g.exactMatch)b="^"+b;if(g.wildcards){b=b.replace(/\\\*/g,".*");b=b.replace(/\\\?/g,".")}var c=null;if(g.ignoreCase)c="i";l=new RegExp(b,c);for(var i=1;i<m.get(0).length&&a<g.maxMultiMatch;i++){if(l.length==0||l.test(m.get(0).options[i].text)){var d=$(m.get(0).options[i]).clone().attr(o,i-1);if(m.data("index")==i)d.text(m.data("text"));u.append(d);a++}}if(a>=1){z.selectedIndex(0)}else if(a==0){u.append(y)}if(a>=g.maxMultiMatch){u.append(x)}z.size(a);u.show();j=null};function parseFloatPx(a){try{a=parseFloat(a.replace(/[\s]*px/,""));if(!isNaN(a))return a}catch(e){}return 0};return};function register(d){var e=$[d]={};$.fn[d]=function(b){b=$.extend(e.defaults,b);var c=this.size();return this.each(function(a){e.execute.call(this,b,c-a)})};return e}})(jQuery);
|
||||
@@ -1,94 +0,0 @@
|
||||
<cfset msStartAt=getTickCount()/>
|
||||
<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)/>
|
||||
<cfset tenant_wz_index=val(mid(request.auth.wz,3,5))/><!--- cut off WZ --->
|
||||
|
||||
<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="iso8601dtFormat"
|
||||
returntype="string"
|
||||
output="false"
|
||||
hint="formates date and time like this: 2023-12-18T15:41:42.516+0300">
|
||||
<cfargument name="input" required="true" />
|
||||
<cfreturn "#dateFormat( input, "yyyy-mm-dd" )#T#timeFormat( input, "HH:mm:ss.lXX" )#"/>
|
||||
</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>
|
||||
|
||||
|
||||
<cfmodule template="mod/payg.cfm"
|
||||
dt_finish=#dt_finish#
|
||||
dt_start=#dt_start#
|
||||
tenant_wz_index=#tenant_wz_index#
|
||||
output="report"
|
||||
debug=#isDefined("DEBUG")#
|
||||
/>
|
||||
<cfset out={
|
||||
"appVersion"=#request.APP_VERSION#,
|
||||
"hours"=#hours#,
|
||||
"dtStart="=#iso8601dtFormat(dt_start)#,
|
||||
"dtFinish"=#iso8601dtFormat(dt_finish)#,
|
||||
"vcdComputingLoadedAt"="#iso8601dtFormat(report.qComputingAge.dt_load)#",
|
||||
"vcdStorageLoadedAt"="#iso8601dtFormat(report.qStorageAge.dt_load)#",
|
||||
"s3StorageLoadedAt"="#iso8601dtFormat(report.qComputingAge.dt_load)#",
|
||||
"s3OpsTrfLoadedAt"="#iso8601dtFormat(report.qS3OpsTrfAge.dt_load)#",
|
||||
"records"=#report.qCharge.recordCount#,
|
||||
"queryDurationMs"=#(getTickCount() - msStartAt)#,
|
||||
"wz"=#request.auth.wz#,
|
||||
"login"=#request.auth.login#,
|
||||
"report"=#report.qCharge.reduce((result, row) => {
|
||||
result.append(row);
|
||||
return result;
|
||||
}, [])#
|
||||
}/>
|
||||
|
||||
<cfcontent
|
||||
type="application/json"
|
||||
/><cfoutput>#serializeJSON(out)#</cfoutput>
|
||||
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
<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>
|
||||
@@ -1,43 +0,0 @@
|
||||
<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>
|
||||
@@ -1,10 +0,0 @@
|
||||
<!--- 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>
|
||||
@@ -1,10 +0,0 @@
|
||||
<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>
|
||||
@@ -1,8 +0,0 @@
|
||||
<!--- 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>
|
||||
@@ -1,24 +0,0 @@
|
||||
<!--- 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>
|
||||
@@ -1,18 +0,0 @@
|
||||
<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>
|
||||