Commit 293f57f9671ade705fed08ea1ad47d5acd97a6bb
1 parent
603a219f
add upload rg group form
Showing
11 changed files
with
365 additions
and
17 deletions
Show diff stats
backend/controllers/ParserController.php
@@ -144,7 +144,6 @@ class ParserController extends BaseController | @@ -144,7 +144,6 @@ class ParserController extends BaseController | ||
144 | ], | 144 | ], |
145 | ]); | 145 | ]); |
146 | 146 | ||
147 | - | ||
148 | $last_index = end( array_flip( $data[0] ) ); | 147 | $last_index = end( array_flip( $data[0] ) ); |
149 | $header_counts = $last_index + 1; | 148 | $header_counts = $last_index + 1; |
150 | //формируем заголовок для пользователя, где он сможет выбрать соответсвие полей (выпадающий список) | 149 | //формируем заголовок для пользователя, где он сможет выбрать соответсвие полей (выпадающий список) |
1 | +<?php | ||
2 | +/** | ||
3 | + * Created by PhpStorm. | ||
4 | + * User: Tsurkanov | ||
5 | + * Date: 27.10.2015 | ||
6 | + * Time: 15:22 | ||
7 | + */ | ||
8 | + | ||
9 | +namespace backend\controllers; | ||
10 | + | ||
11 | +use backend\components\base\BaseController; | ||
12 | +use backend\models\UploadFileRgForm; | ||
13 | +use common\components\CustomVarDamp; | ||
14 | +use common\models\Margins; | ||
15 | +use common\models\MarginsGroups; | ||
16 | +use yii\filters\AccessControl; | ||
17 | +use Yii; | ||
18 | +use yii\web\UploadedFile; | ||
19 | +use yii\data\ArrayDataProvider; | ||
20 | +use yii\multiparser\DynamicFormHelper; | ||
21 | +use common\components\CustomArrayHelper; | ||
22 | + | ||
23 | +class RgGrupController extends BaseController { | ||
24 | + public $layout = "/column"; | ||
25 | + | ||
26 | + /** | ||
27 | + * @inheritdoc | ||
28 | + */ | ||
29 | + public function behaviors() | ||
30 | + { | ||
31 | + return [ | ||
32 | + 'access' => [ | ||
33 | + 'class' => AccessControl::className(), | ||
34 | + 'rules' => [ | ||
35 | + [ | ||
36 | + 'allow' => true, | ||
37 | + 'roles' => ['@'], | ||
38 | + ], | ||
39 | + ], | ||
40 | + ], | ||
41 | +// 'verbs' => [ | ||
42 | +// 'class' => VerbFilter::className(), | ||
43 | +// 'actions' => [ | ||
44 | +// 'logout' => ['post'], | ||
45 | +// ], | ||
46 | +// ], | ||
47 | + ]; | ||
48 | + } | ||
49 | + | ||
50 | + public function actionIndex() | ||
51 | + { | ||
52 | + $model = new UploadFileRgForm(); | ||
53 | + | ||
54 | + return $this->render('index', ['model' => $model]); | ||
55 | + } | ||
56 | + | ||
57 | + public function actionResults() | ||
58 | + { | ||
59 | + $model = new UploadFileRgForm(); | ||
60 | + $data = []; | ||
61 | + | ||
62 | + if ($model->load(Yii::$app->request->post())) { | ||
63 | + $model->file = UploadedFile::getInstance($model, 'file'); | ||
64 | + // первый проход - валидируем, сохраняем файл, ложим в кеш отпарсенные данные и параметры модели (потом при записи в базу данных они пригодятся) | ||
65 | + if ($model->validate()) { | ||
66 | + | ||
67 | + $model->file_path = Yii::getAlias('@manual_upload') . '/' . $model->file->name; | ||
68 | + $model->file->saveAs($model->file_path); | ||
69 | + | ||
70 | + //запускаем парсинг | ||
71 | + $data = $model->readFile(); | ||
72 | + // сохраняем в кеш отпарсенные даные | ||
73 | + Yii::$app->getCache()->set('parser_data', json_encode($data)); | ||
74 | + // сохраняем в кеш модель - в ней настройки для дальнейшей обработки данных | ||
75 | + Yii::$app->getCache()->set('parser_configuration', serialize($model)); | ||
76 | + | ||
77 | + | ||
78 | + } else { | ||
79 | + // не прошла валидация форма загрузки файлов | ||
80 | + $errors_str = ''; | ||
81 | + foreach ($model->getErrors() as $error) { | ||
82 | + $errors_str .= implode( array_values($error) ); | ||
83 | + } | ||
84 | + throw new \ErrorException( $errors_str ); | ||
85 | + } | ||
86 | + // листаем пагинатором, или повторно вызываем - считываем из кеша отпрасенные данные | ||
87 | + } else if (Yii::$app->getCache()->get('parser_data')) { | ||
88 | + | ||
89 | + $data = json_decode(Yii::$app->getCache()->get('parser_data'), true); | ||
90 | + | ||
91 | + } | ||
92 | + $provider = new ArrayDataProvider([ | ||
93 | + 'allModels' => $data, | ||
94 | + 'pagination' => [ | ||
95 | + 'pageSize' => 10, | ||
96 | + ], | ||
97 | + ]); | ||
98 | + | ||
99 | + // создадим модель на столько реквизитов сколько колонок в отпарсенном файле | ||
100 | + $last_index = end( array_flip( $data[0] ) ); | ||
101 | + $header_counts = $last_index + 1; | ||
102 | + $header_model = DynamicFormHelper::CreateDynamicModel( $header_counts ); | ||
103 | + | ||
104 | + // соберем массив данных из которых будет пользователь выбирать значения в конструкторе (выпадающий список) | ||
105 | + $header_array = Margins::getHeader(); | ||
106 | + | ||
107 | + return $this->render('results', | ||
108 | + ['model' => $data, | ||
109 | + 'header_model' => $header_model, | ||
110 | + // список колонок для выбора | ||
111 | + 'basic_column' => $header_array, | ||
112 | + 'dataProvider' => $provider]); | ||
113 | + } | ||
114 | + | ||
115 | + public function actionWrite() | ||
116 | + { | ||
117 | + //получим колонки которые выбрал пользователь | ||
118 | + $arr_attributes = Yii::$app->request->post()['DynamicModel']; | ||
119 | + //соберем модель по полученным данным | ||
120 | + $model = DynamicFormHelper::CreateDynamicModel($arr_attributes); | ||
121 | + //добавим правила валидации (колонки должны быть те что в модели) | ||
122 | + foreach ($arr_attributes as $key => $value) { | ||
123 | + $model->addRule($key, 'in', ['range' => array_keys(Margins::getHeader())]); | ||
124 | + } | ||
125 | + | ||
126 | + // провалидируем выбранные колонки | ||
127 | + if ($model->validate()) { | ||
128 | + | ||
129 | + // валидация успешна у нас есть соответсвие колонок, преобразуем в массив данное соответсвие для дальнейшей работы | ||
130 | + $arr = $model->toArray(); | ||
131 | + | ||
132 | + // получим данные из кеша | ||
133 | + if (Yii::$app->getCache()->get('parser_data') && Yii::$app->getCache()->get('parser_configuration')) { | ||
134 | + $data = json_decode(Yii::$app->getCache()->get('parser_data'), true); | ||
135 | + $configuration = unserialize(Yii::$app->getCache()->get('parser_configuration')); | ||
136 | + } else { | ||
137 | + throw new \ErrorException('Ошибка кеша'); | ||
138 | + } | ||
139 | + | ||
140 | + array_walk($arr, function(&$val){ | ||
141 | + $val = '!'.$val; | ||
142 | + }); | ||
143 | + | ||
144 | + // соотнесем отпарсенные данные с соответсивем полученным от пользователя | ||
145 | + // для этого преобразуем массив отпарсенных данных - назначим ключи согласно соответствию | ||
146 | + $data = CustomArrayHelper::createAssocArray( $data, $arr , 'attr_' ); | ||
147 | + | ||
148 | + // в первой строке у нас заголовки - уберем | ||
149 | + unset($data[0]); | ||
150 | + // подготовим данные для записи в таблицу w_margins_groups | ||
151 | + //$arr_values = []; | ||
152 | + $group = ''; | ||
153 | + $importer_id = $configuration['importer_id']; | ||
154 | + foreach ($data as $row_data) { | ||
155 | + | ||
156 | + if (isset($row_data['!group'])) { | ||
157 | + $group = $row_data['!group']; | ||
158 | + unset($row_data['!group']); | ||
159 | + } | ||
160 | + if (isset($row_data['!_null'])) { | ||
161 | + unset($row_data['!_null']); | ||
162 | + } | ||
163 | + | ||
164 | + foreach ($row_data as $key => $value) { | ||
165 | + if($group) | ||
166 | + $row['group'] = trim( $group ); | ||
167 | + | ||
168 | + $row['importer_id'] = trim( $importer_id ); | ||
169 | + $row['margin_id'] = ltrim($key,'!'); | ||
170 | + $row['koef'] = \Yii::$app->converter->convertTo( 'float', $value ); | ||
171 | + | ||
172 | + // сохраним подготовленные данные | ||
173 | + $margins_groups = new MarginsGroups(); | ||
174 | + $margins_groups->attributes = $row; | ||
175 | + | ||
176 | + if ( !$margins_groups->save() ) { | ||
177 | + $errors_str = ''; | ||
178 | + foreach ($margins_groups->getErrors() as $error) { | ||
179 | + $errors_str .= implode( array_values($error) ); | ||
180 | + } | ||
181 | + throw new \ErrorException( $errors_str ); | ||
182 | + } | ||
183 | + } | ||
184 | + | ||
185 | + Yii::$app->session->setFlash('success'); | ||
186 | + // все прошло успешно - очищаем кеш | ||
187 | + Yii::$app->getCache()->delete('parser_data'); | ||
188 | + Yii::$app->getCache()->delete('parser_configuration'); | ||
189 | + | ||
190 | + if( file_exists($configuration['file_path']) ) | ||
191 | + unlink($configuration['file_path']); | ||
192 | + | ||
193 | + return $this->render('index', ['model' => $configuration]); | ||
194 | + | ||
195 | + | ||
196 | + | ||
197 | + } | ||
198 | + | ||
199 | + } | ||
200 | + | ||
201 | + } | ||
202 | +} | ||
0 | \ No newline at end of file | 203 | \ No newline at end of file |
1 | +<?php | ||
2 | +namespace backend\models; | ||
3 | + | ||
4 | +use yii\base\ErrorException; | ||
5 | +use yii\base\Model; | ||
6 | +use yii\web\UploadedFile; | ||
7 | +use Yii; | ||
8 | +use common\components\CustomVarDamp; | ||
9 | + | ||
10 | +/** | ||
11 | + * UploadForm is the model behind the upload form. | ||
12 | + */ | ||
13 | +class UploadFileRgForm extends Model | ||
14 | +{ | ||
15 | + /** | ||
16 | + * @var UploadedFile file attribute | ||
17 | + */ | ||
18 | + // атрибуты формы | ||
19 | + public $file; | ||
20 | + public $file_path; | ||
21 | + public $importer_id; | ||
22 | + | ||
23 | + | ||
24 | + | ||
25 | + public function rules() | ||
26 | + { | ||
27 | + return [ | ||
28 | + ['file', 'required', 'message' => 'Не выбран файл!' ], | ||
29 | + ['importer_id', 'required', 'message' => 'Не указан поставщик!' ], | ||
30 | + [['file'], 'file', 'extensions' => 'xlsx', 'checkExtensionByMimeType'=>false ] | ||
31 | + ]; | ||
32 | + } | ||
33 | + | ||
34 | + public function attributeLabels() | ||
35 | + { | ||
36 | + return [ | ||
37 | + 'file' => Yii::t('app', 'Источник'), | ||
38 | + 'importer_id' => Yii::t('app', 'Поставщик'), | ||
39 | + ]; | ||
40 | + } | ||
41 | + | ||
42 | + public function readFile( $options = [] ){ | ||
43 | + | ||
44 | + $data = Yii::$app->multiparser->parse( $this->file_path, $options ); | ||
45 | + if( !is_array( $data ) ){ | ||
46 | + throw new ErrorException("Ошибка чтения из файла RG групп {$this->file_path}"); | ||
47 | + } | ||
48 | + | ||
49 | + | ||
50 | + return $data; | ||
51 | + } | ||
52 | + | ||
53 | + function __destruct() | ||
54 | + { | ||
55 | + // файл больше не нужен - данные прочитаны и сохранены в кеш | ||
56 | + // if( file_exists($this->file_path) ) | ||
57 | + // unlink($this->file_path); | ||
58 | + } | ||
59 | + | ||
60 | + | ||
61 | +} | ||
0 | \ No newline at end of file | 62 | \ No newline at end of file |
backend/views/layouts/column.php
@@ -283,6 +283,8 @@ $this->beginContent('@app/views/layouts/main.php'); | @@ -283,6 +283,8 @@ $this->beginContent('@app/views/layouts/main.php'); | ||
283 | 'options' => ['class' => 'sidebar-menu'], | 283 | 'options' => ['class' => 'sidebar-menu'], |
284 | 'items' => [ | 284 | 'items' => [ |
285 | ['label' => "Загрузка файлов", 'url' => ['#'], 'items' => [ | 285 | ['label' => "Загрузка файлов", 'url' => ['#'], 'items' => [ |
286 | + ['label' => 'Кросс файлы', 'url' => ['crossing-upload/index']], | ||
287 | + ['label' => 'Группы RG', 'url' => ['rg-grup/index']], | ||
286 | ['label' => 'Файлы на сервере', 'url' => ['parser/server-files']], | 288 | ['label' => 'Файлы на сервере', 'url' => ['parser/server-files']], |
287 | ['label' => 'Загрузить файл на сервер', 'url' => ['parser/index', 'mode' => 1]], | 289 | ['label' => 'Загрузить файл на сервер', 'url' => ['parser/index', 'mode' => 1]], |
288 | ['label' => 'Ручная загрузка', 'url' => ['parser/index']], | 290 | ['label' => 'Ручная загрузка', 'url' => ['parser/index']], |
1 | +<?php | ||
2 | +use yii\widgets\ActiveForm; | ||
3 | +use yii\helpers\Html; | ||
4 | +use backend\models\Importers; | ||
5 | +use yii\helpers\ArrayHelper; | ||
6 | + | ||
7 | +$button_label = 'Прочитать'; | ||
8 | + | ||
9 | + | ||
10 | +?> | ||
11 | +<div class="row"> | ||
12 | + <div class="col-lg-5"> | ||
13 | + <?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data',],'action'=>['rg-grup/results']]); | ||
14 | + | ||
15 | + if ($msg = \Yii::$app->session->getFlash('success')) { // вернулись после успешной загрузки данного файла | ||
16 | + echo Html::tag('h3', $msg ,['class'=>'bg-success']); | ||
17 | + } | ||
18 | + ?> | ||
19 | + <h3>Загрузка RG групп поставщиков</h3> | ||
20 | + | ||
21 | + | ||
22 | + <?= $form->field($model, 'importer_id')->dropDownList(ArrayHelper::map( Importers::find()->all(), 'id','name' )); ?> | ||
23 | + | ||
24 | + | ||
25 | + <?= $form->field($model, 'file')->fileInput()->label(false) ?> | ||
26 | + <div class="form-group"> | ||
27 | + <?= Html::submitButton(Yii::t( 'app', $button_label ), ['class' => 'btn btn-primary']) ?> | ||
28 | + </div> | ||
29 | + | ||
30 | + <?php ActiveForm::end() ?> | ||
31 | + </div> | ||
32 | +</div> | ||
33 | + |
1 | +<?php | ||
2 | + | ||
3 | +use yii\helpers\Html; | ||
4 | +use yii\multiparser\DynamicFormHelper; | ||
5 | +use yii\widgets\ActiveForm; | ||
6 | + | ||
7 | + | ||
8 | +/* @var $this yii\web\View */ | ||
9 | +/* @var $searchModel backend\models\CatalogSearch */ | ||
10 | +/* @var $dataProvider yii\data\ActiveDataProvider */ | ||
11 | + | ||
12 | +$this->title = 'Отпарсенные данные файла'; | ||
13 | +$this->params['breadcrumbs'][] = $this->title; | ||
14 | +?> | ||
15 | +<div class="catalog-index"> | ||
16 | + | ||
17 | + <h1><?= Html::encode($this->title) ?></h1> | ||
18 | + <?php // echo $this->render('_search', ['model' => $searchModel]); | ||
19 | + | ||
20 | + | ||
21 | + $form = ActiveForm::begin(['action' => 'write']); | ||
22 | + ?> | ||
23 | + <?= DynamicFormHelper::CreateGridWithDropDownListHeader( $dataProvider, $form, $header_model, $basic_column )?> | ||
24 | + | ||
25 | + <div class="form-group"> | ||
26 | + <?= Html::submitButton(Yii::t('app', 'Записать в БД'), ['class' => 'btn btn-primary']) ?> | ||
27 | + </div> | ||
28 | + | ||
29 | + <?php ActiveForm::end() ?> | ||
30 | + <?= Html::a('Вернуться', ['rg-grup/index'], ['class' => 'btn btn-primary', 'name' => 'Return',]) ?> | ||
31 | + | ||
32 | +</div> | ||
0 | \ No newline at end of file | 33 | \ No newline at end of file |
common/components/CustomArrayHelper.php
@@ -34,8 +34,8 @@ class CustomArrayHelper extends \yii\helpers\ArrayHelper { | @@ -34,8 +34,8 @@ class CustomArrayHelper extends \yii\helpers\ArrayHelper { | ||
34 | return $value !== ''; | 34 | return $value !== ''; |
35 | }); | 35 | }); |
36 | } | 36 | } |
37 | + array_walk( $value_arr, | ||
37 | 38 | ||
38 | - array_walk($value_arr, | ||
39 | function (&$value, $key, $key_array) { | 39 | function (&$value, $key, $key_array) { |
40 | $res = $value; | 40 | $res = $value; |
41 | foreach ($res as $sub_key => $sub_value) { | 41 | foreach ($res as $sub_key => $sub_value) { |
@@ -46,12 +46,13 @@ class CustomArrayHelper extends \yii\helpers\ArrayHelper { | @@ -46,12 +46,13 @@ class CustomArrayHelper extends \yii\helpers\ArrayHelper { | ||
46 | $res[$new_key] = $value[$sub_key]; | 46 | $res[$new_key] = $value[$sub_key]; |
47 | } | 47 | } |
48 | } | 48 | } |
49 | - unset($res[$sub_key]); | ||
50 | - $value = $res; | 49 | + unset($res[$sub_key]); |
50 | + $value = $res; | ||
51 | } | 51 | } |
52 | 52 | ||
53 | }, | 53 | }, |
54 | - $key_array); | 54 | + |
55 | + $key_array ); | ||
55 | 56 | ||
56 | return $value_arr; | 57 | return $value_arr; |
57 | } | 58 | } |
common/components/parsers/config.php
@@ -71,8 +71,8 @@ | @@ -71,8 +71,8 @@ | ||
71 | ['web' => | 71 | ['web' => |
72 | ['class' => 'yii\multiparser\XlsxParser', | 72 | ['class' => 'yii\multiparser\XlsxParser', |
73 | 'path_for_extract_files' => \Yii::getAlias('@temp_upload') . '/xlsx/', | 73 | 'path_for_extract_files' => \Yii::getAlias('@temp_upload') . '/xlsx/', |
74 | - 'has_header_row' => true, | ||
75 | - 'active_sheet' => 2, | 74 | + // 'has_header_row' => true, |
75 | + 'active_sheet' => 1, | ||
76 | 'converter_conf' => [ | 76 | 'converter_conf' => [ |
77 | 'class' => 'common\components\parsers\CustomConverter', | 77 | 'class' => 'common\components\parsers\CustomConverter', |
78 | 'configuration' => ["string" => []], | 78 | 'configuration' => ["string" => []], |
common/models/Margins.php
@@ -45,4 +45,22 @@ class Margins extends \yii\db\ActiveRecord | @@ -45,4 +45,22 @@ class Margins extends \yii\db\ActiveRecord | ||
45 | 'koef' => 'Коэффициент', | 45 | 'koef' => 'Коэффициент', |
46 | ]; | 46 | ]; |
47 | } | 47 | } |
48 | + | ||
49 | + // возвращает массив для выбора в динамических формах (конструкторах) | ||
50 | + public static function getHeader() | ||
51 | + { | ||
52 | + $header_array = self::find()->asArray()->all(); | ||
53 | + | ||
54 | + $id_arr = array_column($header_array,'id'); | ||
55 | + $name_arr = array_column($header_array,'name'); | ||
56 | + $header_array = array_combine( $id_arr, $name_arr ); | ||
57 | + $header_array['_null'] = null; // первая колонка пустая | ||
58 | + $header_array['group'] = 'Группа RG'; | ||
59 | + ksort($header_array); | ||
60 | + | ||
61 | + return $header_array; | ||
62 | + } | ||
63 | + | ||
64 | + | ||
65 | + | ||
48 | } | 66 | } |
composer.lock
@@ -12,13 +12,13 @@ | @@ -12,13 +12,13 @@ | ||
12 | "version": "dev-master", | 12 | "version": "dev-master", |
13 | "source": { | 13 | "source": { |
14 | "type": "git", | 14 | "type": "git", |
15 | - "url": "git@github.com:tsurkanovm/yii-multiparser.git", | ||
16 | - "reference": "d1fac7a9ab175babccfe47e9a448528b154db928" | 15 | + "url": "https://github.com/tsurkanovm/yii-multiparser.git", |
16 | + "reference": "0c6fd004d8739f106a58f584661e1e5327958b34" | ||
17 | }, | 17 | }, |
18 | "dist": { | 18 | "dist": { |
19 | "type": "zip", | 19 | "type": "zip", |
20 | - "url": "https://api.github.com/repos/tsurkanovm/yii-multiparser/zipball/d1fac7a9ab175babccfe47e9a448528b154db928", | ||
21 | - "reference": "d1fac7a9ab175babccfe47e9a448528b154db928", | 20 | + "url": "https://api.github.com/repos/tsurkanovm/yii-multiparser/zipball/0c6fd004d8739f106a58f584661e1e5327958b34", |
21 | + "reference": "0c6fd004d8739f106a58f584661e1e5327958b34", | ||
22 | "shasum": "" | 22 | "shasum": "" |
23 | }, | 23 | }, |
24 | "require": { | 24 | "require": { |
@@ -50,7 +50,7 @@ | @@ -50,7 +50,7 @@ | ||
50 | "xml", | 50 | "xml", |
51 | "yii2" | 51 | "yii2" |
52 | ], | 52 | ], |
53 | - "time": "2015-10-27 11:59:34" | 53 | + "time": "2015-10-28 09:28:22" |
54 | }, | 54 | }, |
55 | { | 55 | { |
56 | "name": "bower-asset/bootstrap", | 56 | "name": "bower-asset/bootstrap", |
vendor/composer/installed.json
@@ -1050,19 +1050,19 @@ | @@ -1050,19 +1050,19 @@ | ||
1050 | "version_normalized": "9999999-dev", | 1050 | "version_normalized": "9999999-dev", |
1051 | "source": { | 1051 | "source": { |
1052 | "type": "git", | 1052 | "type": "git", |
1053 | - "url": "git@github.com:tsurkanovm/yii-multiparser.git", | ||
1054 | - "reference": "d1fac7a9ab175babccfe47e9a448528b154db928" | 1053 | + "url": "https://github.com/tsurkanovm/yii-multiparser.git", |
1054 | + "reference": "0c6fd004d8739f106a58f584661e1e5327958b34" | ||
1055 | }, | 1055 | }, |
1056 | "dist": { | 1056 | "dist": { |
1057 | "type": "zip", | 1057 | "type": "zip", |
1058 | - "url": "https://api.github.com/repos/tsurkanovm/yii-multiparser/zipball/d1fac7a9ab175babccfe47e9a448528b154db928", | ||
1059 | - "reference": "d1fac7a9ab175babccfe47e9a448528b154db928", | 1058 | + "url": "https://api.github.com/repos/tsurkanovm/yii-multiparser/zipball/0c6fd004d8739f106a58f584661e1e5327958b34", |
1059 | + "reference": "0c6fd004d8739f106a58f584661e1e5327958b34", | ||
1060 | "shasum": "" | 1060 | "shasum": "" |
1061 | }, | 1061 | }, |
1062 | "require": { | 1062 | "require": { |
1063 | "yiisoft/yii2": "*" | 1063 | "yiisoft/yii2": "*" |
1064 | }, | 1064 | }, |
1065 | - "time": "2015-10-27 11:59:34", | 1065 | + "time": "2015-10-28 09:28:22", |
1066 | "type": "library", | 1066 | "type": "library", |
1067 | "installation-source": "dist", | 1067 | "installation-source": "dist", |
1068 | "autoload": { | 1068 | "autoload": { |