TemplateLibraryApiService.php 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  1. <?php
  2. /**
  3. * 模版站api服务类
  4. * @copyright 2021-浙江引擎力营销策划有限公司
  5. * @author Lc<sunshinecc1@163.com>
  6. * @since 2021-08-23
  7. */
  8. namespace App\Http\Services;
  9. use App\Http\Traits\TemplateLibraryTool;
  10. use Illuminate\Support\Facades\DB;
  11. use Illuminate\Database\Eloquent\Model;
  12. use Illuminate\Database\Query\Builder;
  13. use Illuminate\Contracts\Pagination\LengthAwarePaginator;
  14. use Illuminate\Support\Collection;
  15. class TemplateLibraryApiService
  16. {
  17. use TemplateLibraryTool;
  18. /**
  19. * 获取页面\模版\变量关联列表
  20. * @param $siteId
  21. * @return array
  22. */
  23. public function getContentList($siteId)
  24. {
  25. $connection = DB::connection($this->connection($siteId));
  26. $contentList = $connection->table('content')
  27. ->leftJoin('content_template', 'content.tpl_id', '=', 'content_template.id')
  28. ->whereIn('content.status', [1, 2])
  29. ->select('content.*', 'content_template.name')
  30. ->orderBy('content.parent_id', 'asc')
  31. ->orderBy('content.rank', 'asc')->get();
  32. $contentRelateVariableIds = $connection->table('content_template_relate')->get();
  33. foreach ($contentList as $value) {
  34. $value->variableIds = [];
  35. foreach ($contentRelateVariableIds as $vv) {
  36. if ($value->tpl_id == $vv->tid) {
  37. $value->variableIds[] = $vv->vid;
  38. }
  39. }
  40. }
  41. $contentVariableList = $connection->table('content_template_var')->get();
  42. foreach ($contentList as $item) {
  43. $item->variableList = [];
  44. foreach ($item->variableIds as $vv) {
  45. foreach ($contentVariableList as $value) {
  46. if ($vv == $value->id) {
  47. $item->variableList[] = $value;
  48. }
  49. }
  50. }
  51. }
  52. $contentList = json_decode($contentList->toJson(), true);
  53. $conditions = [];
  54. foreach ($contentList as $key => $item) {
  55. foreach ($item['variableList'] as $kk => $value) {
  56. $contentList[$key]['variableList'][$kk]['input_opts'] = explode("\r\n", $value['input_opts']) ?? [];
  57. $contentList[$key]['variableList'][$kk]['value'] = $value['input_value'] ?? '';
  58. $conditions[] = [
  59. 'key' => $value['name'],
  60. 'content_id' => $item['id'],
  61. ];
  62. }
  63. }
  64. $result = json_decode($connection->table('content_var')->get()->toJson(), true);
  65. $lists = [];
  66. foreach ($conditions as $item) {
  67. foreach ($result as $value) {
  68. if ($item['key'] == $value['key'] && $item['content_id'] == $value['content_id']) {
  69. $key = $item['content_id'] . '--' . $item['key'];
  70. $lists[$key] = $value['value'];
  71. }
  72. }
  73. }
  74. foreach ($contentList as $key => $item) {
  75. foreach ($item['variableList'] as $kk => $value) {
  76. $arrayKey = $item['id'] . '--' . $value['name'];
  77. $val = $lists[$arrayKey] ?? '';
  78. if (!empty($val)) {
  79. $contentList[$key]['variableList'][$kk]['value'] = $val;
  80. if ($value['input_type'] == 'checkbox' || $value['input_type'] == 'resource' || $value['input_type'] == 'file' || $value['input_type'] == 'image') {
  81. $contentList[$key]['variableList'][$kk]['value'] = unserialize($val) ?? [];
  82. }
  83. if ($value['input_type'] == 'date') {
  84. $contentList[$key]['variableList'][$kk]['value'] = date('Y-m-d', strtotime($val));
  85. }
  86. }
  87. }
  88. }
  89. $templateList = $connection->table('content_template')->pluck('name', 'id');
  90. $list = [];
  91. foreach ($contentList as $value) {
  92. $last_names = array_column($value['variableList'], 'rank');
  93. array_multisort($last_names, SORT_ASC, $value['variableList']);
  94. $publishTime = '';
  95. if (!empty($value['publish_time'])) {
  96. $publishTime = date('Y-m-d', $value['publish_time']) ?? '';
  97. }
  98. $expiredTime = '';
  99. if (!empty($value['expired_time'])) {
  100. $expiredTime = date('Y-m-d', $value['expired_time']) ?? '';
  101. }
  102. $data = [
  103. 'id' => $value['id'] ?? 0,
  104. 'subtitle' => $value['subtitle'] ?? '',
  105. 'parent_id' => $value['parent_id'] ?? 0,
  106. 'name' => "{$value['title']}(#{$value['id']})",
  107. 'title' => $value['title'] ?? '',
  108. 'thumb' => $value['thumb'] ?? '',
  109. 'summary' => $value['summary'] ?? '',
  110. 'content_type' => $value['content_type'] ?? '',
  111. 'menu_text' => $value['menu_text'] ?? '',
  112. 'uri' => $value['uri'] ?? '',
  113. 'alias' => $value['alias'] ?? '',
  114. 'content' => $value['content'] ?? '',
  115. 'tpl_id' => $value['tpl_id'] ?? 0,
  116. 'tplName' => $templateList[$value['tpl_id']] ?? '',
  117. 'css_id' => $value['css_id'] ?? 0,
  118. 'cssName' => $templateList[$value['css_id']] ?? '',
  119. 'deny_spider' => $value['deny_spider'] ?? '',
  120. 'is_enabled' => $value['is_enabled'] ?? 0,
  121. 'is_301' => $value['is_301'] ?? 0,
  122. 'is_freeze_url' => $value['is_freeze_url'] ?? 0,
  123. 'is_hidemenu' => $value['is_hidemenu'] ?? 0,
  124. 'redirect' => $value['redirect'] ?? '',
  125. 'status' => $value['status'],
  126. 'publish_time' => $publishTime,
  127. 'expired_time' => $expiredTime,
  128. 'rank' => $value['rank'] ?? '',
  129. 'seo_title' => $value['seo_title'] ?? '',
  130. 'seo_keywords' => $value['seo_keywords'] ?? '',
  131. 'seo_description' => $value['seo_description'] ?? '',
  132. 'variable_list' => $value['variableList'],
  133. ];
  134. $list[] = $data;
  135. }
  136. ksort($list);
  137. return list_to_tree($list, 'id', 'parent_id', 'children');
  138. }
  139. public function getWebSitePage($siteId)
  140. {
  141. $connection = DB::connection($this->connection($siteId));
  142. $contentList = $connection->table('content')
  143. ->leftJoin('content_template', 'content.tpl_id', '=', 'content_template.id')
  144. ->whereIn('content.status', [1, 2])
  145. ->select('content.*', 'content_template.name')
  146. ->orderBy('content.parent_id', 'asc')
  147. ->orderBy('content.rank', 'asc')->get()->toJson();
  148. $contentList = json_decode($contentList, true);
  149. $templateList = $connection->table('content_template')->pluck('name', 'id');
  150. foreach ($contentList as $value) {
  151. $publishTime = '';
  152. if (!empty($value['publish_time'])) {
  153. $publishTime = date('Y-m-d', $value['publish_time']) ?? '';
  154. }
  155. $expiredTime = '';
  156. if (!empty($value['expired_time'])) {
  157. $expiredTime = date('Y-m-d', $value['expired_time']) ?? '';
  158. }
  159. $data = [
  160. 'id' => $value['id'] ?? 0,
  161. 'subtitle' => $value['subtitle'] ?? '',
  162. 'parent_id' => $value['parent_id'] ?? 0,
  163. 'name' => "{$value['title']}(#{$value['id']})",
  164. 'title' => $value['title'] ?? '',
  165. 'thumb' => $value['thumb'] ?? '',
  166. 'summary' => $value['summary'] ?? '',
  167. 'content_type' => $value['content_type'] ?? '',
  168. 'menu_text' => $value['menu_text'] ?? '',
  169. 'uri' => $value['uri'] ?? '',
  170. 'alias' => $value['alias'] ?? '',
  171. 'content' => $value['content'] ?? '',
  172. 'tpl_id' => $value['tpl_id'] ?? 0,
  173. 'tplName' => $templateList[$value['tpl_id']] ?? '',
  174. 'css_id' => $value['css_id'] ?? 0,
  175. 'cssName' => $templateList[$value['css_id']] ?? '',
  176. 'deny_spider' => $value['deny_spider'] ?? '',
  177. 'is_enabled' => $value['is_enabled'] ?? 0,
  178. 'is_301' => $value['is_301'] ?? 0,
  179. 'is_freeze_url' => $value['is_freeze_url'] ?? 0,
  180. 'is_hidemenu' => $value['is_hidemenu'] ?? 0,
  181. 'redirect' => $value['redirect'] ?? '',
  182. 'status' => $value['status'],
  183. 'publish_time' => $publishTime,
  184. 'expired_time' => $expiredTime,
  185. 'rank' => $value['rank'] ?? '',
  186. 'seo_title' => $value['seo_title'] ?? '',
  187. 'seo_keywords' => $value['seo_keywords'] ?? '',
  188. 'seo_description' => $value['seo_description'] ?? '',
  189. ];
  190. $list[] = $data;
  191. }
  192. ksort($list);
  193. return list_to_tree($list, 'id', 'parent_id', 'children');
  194. }
  195. /**
  196. * 获取所有页面列表
  197. * @param $siteId int 项目id
  198. * @param $tplId int 模版id
  199. * @param $notTplId int 排除的模版id
  200. * @return array|Builder|Collection|mixed
  201. */
  202. public function getWebsitePageList($siteId, $tplId, $notTplId)
  203. {
  204. $connection = DB::connection($this->connection($siteId));
  205. $contentList = $connection->table('content');
  206. if (!empty($tplId)) {
  207. $contentList->where('tpl_id', $tplId);
  208. }
  209. if (!empty($notTplId)) {
  210. $notTplId = explode(',', $notTplId);
  211. $contentList->whereNotIn('tpl_id', $notTplId);
  212. }
  213. $contentList = $contentList
  214. ->whereIn('status', [1, 2])
  215. ->orderBy('parent_id', 'asc')
  216. ->orderBy('rank', 'asc')->get();
  217. $contentList = json_decode($contentList->toJson(), true);
  218. $templateList = $connection->table('content_template')->pluck('name', 'id');
  219. foreach ($contentList as $key => $item) {
  220. $contentList[$key]['tplName'] = $templateList[$item['tpl_id']] ?? '';
  221. $contentList[$key]['cssName'] = $templateList[$item['css_id']] ?? '';
  222. }
  223. //return list_to_tree($contentList, 'id', 'parent_id', 'children');
  224. return $this->listToTreeRecursive($contentList, 0, 'id', 'parent_id', 'children');
  225. }
  226. /**
  227. * 根据页面id获取模版列表
  228. * @param $siteId
  229. * @param $pageId
  230. * @param $uri
  231. * @return Model|Builder|object|null
  232. */
  233. public function getWebsitePageDetailsByUri($siteId, $pageId, $uri)
  234. {
  235. $connection = DB::connection($this->connection($siteId));
  236. $contentInfo = $connection
  237. ->table('content')
  238. ->whereIn('status', [1, 2]);
  239. if (!empty($pageId)) {
  240. $contentInfo = $contentInfo->where('id', $pageId);
  241. }
  242. if (!empty($uri)) {
  243. $contentInfo = $contentInfo->where('uri', $uri);
  244. }
  245. $contentInfo = $contentInfo->first();
  246. if (!empty($contentInfo)) {
  247. $contentInfo->cssName = $connection->table('content_template')->where('id', $contentInfo->css_id)->value('name') ?? '';
  248. $contentInfo->tplName = $connection->table('content_template')->where('id', $contentInfo->tpl_id)->value('name') ?? '';
  249. $contentRelateVariableIds = $connection->table('content_template_relate')->get();
  250. $contentInfo->variableIds = [];
  251. foreach ($contentRelateVariableIds as $vv) {
  252. if ($contentInfo->tpl_id == $vv->tid) {
  253. $contentInfo->variableIds[] = $vv->vid;
  254. }
  255. }
  256. $contentVariableList = $connection->table('content_template_var')->get();
  257. $contentInfo->variableList = [];
  258. foreach ($contentInfo->variableIds as $vv) {
  259. foreach ($contentVariableList as $value) {
  260. if ($vv == $value->id) {
  261. $contentInfo->variableList[] = $value;
  262. }
  263. }
  264. }
  265. $contentInfo = \GuzzleHttp\json_decode(json_encode($contentInfo), true);
  266. foreach ($contentInfo['variableList'] as $kk => $value) {
  267. $contentInfo['variableList'][$kk]['input_opts'] = explode("\r\n", $value['input_opts']) ?? [];
  268. $contentInfo['variableList'][$kk]['value'] = $value['input_value'] ?? '';
  269. $result = $connection
  270. ->table('content_var')
  271. ->where('key', $value['name'])
  272. ->where('content_id', $contentInfo['id'])->value('value');
  273. if (!empty($result)) {
  274. $contentInfo['variableList'][$kk]['value'] = $result;
  275. if ($value['input_type'] == 'checkbox' || $value['input_type'] == 'resource' || $value['input_type'] == 'file' || $value['input_type'] == 'image') {
  276. $contentInfo['variableList'][$kk]['value'] = unserialize($result) ?? [];
  277. }
  278. if ($value['input_type'] == 'date') {
  279. $contentInfo['variableList'][$kk]['value'] = date('Y-m-d', strtotime($result));
  280. }
  281. }
  282. }
  283. }
  284. return $contentInfo;
  285. }
  286. /**
  287. * 根据页面Id获取页面的子页面列表
  288. * @param $siteId
  289. * @param $parentId
  290. * @param $tplId
  291. * @param $notTplId
  292. * @param $sortBy
  293. * @param $all
  294. * @param $pageSize
  295. * @return LengthAwarePaginator|Builder
  296. */
  297. public function getChildWebsitePageListByPageId($siteId, $parentId, $tplId, $notTplId, $sortBy, $all, $pageSize)
  298. {
  299. $connection = DB::connection($this->connection($siteId));
  300. $contentList = $connection->table('content')->whereIn('status', [1, 2]);
  301. //是否筛选pid下所有的
  302. if ($all) {
  303. $parentPageList = $connection->table('content')->where('parent_id', $parentId)->get();
  304. $childPageList = $this->recursion($parentPageList, $siteId);
  305. $pageIds = array_column($childPageList, 'id');
  306. $contentList->whereIn('id', $pageIds);
  307. }
  308. if (!empty($parentId) && !$all) {
  309. $contentList->where('parent_id', $parentId);
  310. }
  311. if (!empty($notTplId)) {
  312. $notTplId = explode(',', $notTplId);
  313. $contentList->whereNotIn('tpl_id', $notTplId);
  314. }
  315. if (!empty($tplId)) {
  316. $contentList->where('tpl_id', $tplId);
  317. }
  318. //排序方式
  319. if ($sortBy == 'random') {
  320. $filed = ['tpl_id', 'title', 'parent_id', 'alias'];
  321. $filedKey = array_rand($filed);
  322. $sort = ['desc', 'asc'];
  323. $sortKey = array_rand($sort, 1);
  324. $contentList->orderBy($filed[$filedKey], $sort[$sortKey]);
  325. }
  326. if ($sortBy == true) {
  327. $contentList->orderBy('publish_time', 'desc');
  328. }
  329. if ($sortBy == false) {
  330. $contentList->orderBy('id', 'asc');
  331. }
  332. $contentList = $contentList->paginate($pageSize);
  333. $contentRelateVariableIds = $connection->table('content_template_relate')->get();
  334. $contentVariableList = $connection->table('content_template_var')->get();
  335. foreach ($contentList as $value) {
  336. $value->cssName = $connection->table('content_template')->where('id', $value->css_id)->value('name') ?? '';
  337. $value->tplName = $connection->table('content_template')->where('id', $value->tpl_id)->value('name') ?? '';
  338. $value->variableIds = [];
  339. foreach ($contentRelateVariableIds as $vv) {
  340. if ($value->tpl_id == $vv->tid) {
  341. $value->variableIds[] = $vv->vid;
  342. }
  343. }
  344. $value->variableList = [];
  345. foreach ($value->variableIds as $vv) {
  346. foreach ($contentVariableList as $vvv) {
  347. if ($vv == $vvv->id) {
  348. $value->variableList[] = $vvv;
  349. }
  350. }
  351. }
  352. $value = \GuzzleHttp\json_decode(json_encode($value), true);
  353. foreach ($value['variableList'] as $kk => $vv) {
  354. $value['variableList'][$kk]['input_opts'] = explode("\r\n", $vv['input_opts']) ?? [];
  355. $value['variableList'][$kk]['value'] = $vv['input_value'] ?? '';
  356. $result = $connection
  357. ->table('content_var')
  358. ->where('key', $vv['name'])
  359. ->where('content_id', $vv['id'])->value('value');
  360. if (!empty($result)) {
  361. $value['variableList'][$kk]['value'] = $result;
  362. if ($vv['input_type'] == 'checkbox' || $vv['input_type'] == 'resource' || $vv['input_type'] == 'file' || $vv['input_type'] == 'image') {
  363. $value['variableList'][$kk]['value'] = unserialize($result) ?? [];
  364. }
  365. if ($vv['input_type'] == 'date') {
  366. $value['variableList'][$kk]['value'] = date('Y-m-d', strtotime($result));
  367. }
  368. }
  369. }
  370. }
  371. return $contentList;
  372. }
  373. /**
  374. * 搜索
  375. * @param $siteId
  376. * @param $keyword
  377. * @param $pageSize
  378. * @param $tplId
  379. * @param $notTplId
  380. * @return LengthAwarePaginator|Builder
  381. */
  382. public function search($siteId, $keyword, $pageSize, $tplId, $notTplId)
  383. {
  384. $connection = DB::connection($this->connection($siteId));
  385. $contentList = $connection->table('content')
  386. ->whereIn('status', [1, 2])
  387. ->where('deny_spider', 0);
  388. if (!empty($keyword)) {
  389. $contentList->where('title', 'like', '%' . $keyword . '%');
  390. }
  391. if (!empty($tplId)) {
  392. $contentList->where('tpl_id', $tplId);
  393. }
  394. if (!empty($notTplId)) {
  395. $notTplId = explode(',', $notTplId);
  396. $contentList->whereNotIn('tpl_id', $notTplId);
  397. }
  398. $contentList = $contentList->paginate($pageSize);
  399. if (!empty($contentList)) {
  400. $templateList = $connection->table('content_template')->pluck('name', 'id');
  401. foreach ($contentList as $item) {
  402. $item->cssName = $templateList[$item->css_id] ?? '';
  403. $item->tplName = $templateList[$item->tpl_id] ?? '';
  404. }
  405. }
  406. return $contentList;
  407. }
  408. /**
  409. * 广告列表
  410. * @param $siteId
  411. * @return Collection
  412. */
  413. public function getAdvertiseList($siteId)
  414. {
  415. $connection = DB::connection($this->connection($siteId));
  416. $contentList = $connection->table('advert')->get();
  417. $advertElementList = $connection->table('advert_element')->get();
  418. foreach ($contentList as $value) {
  419. $value->advertElementList = [];
  420. foreach ($advertElementList as $item) {
  421. if ($value->id == $item->advert_id) {
  422. $value->advertElementList[] = $item;
  423. }
  424. }
  425. }
  426. return $contentList;
  427. }
  428. /**
  429. * 获取语言环境
  430. * @param $siteId
  431. * @return Model|Builder|object|null
  432. */
  433. public function getLanguage($siteId)
  434. {
  435. $connection = DB::connection($this->connection($siteId));
  436. $contentInfo = $connection->table('language')
  437. ->where('code', 'en')
  438. ->select('code', 'name', 'chinese')
  439. ->where('is_enabled', 1)->first();
  440. return $contentInfo;
  441. }
  442. /**
  443. * 提交表单
  444. * @param $request
  445. * @return bool
  446. */
  447. public function formSubmission($request)
  448. {
  449. $connection = DB::connection($this->connection($request['siteId']));
  450. $content = '';
  451. if (!empty($request['list'])) {
  452. $content = json_encode($request['list']);
  453. }
  454. $update = [
  455. 'sender_name' => $request['name'],
  456. 'sender_email' => $request['email'],
  457. 'content' => $content,
  458. 'user_id' => 0,
  459. 'sender_uid' => 0,
  460. 'title' => '',
  461. 'client_ip' => 0,
  462. 'is_read' => 0,
  463. 'is_delete' => 0,
  464. 'mail_time' => 0,
  465. 'mail_response' => 0,
  466. 'create_time' => time(),
  467. ];
  468. $contentInfo = $connection->table('user_msg')->insert($update);
  469. return $contentInfo;
  470. }
  471. /**
  472. * 数据库连接信息
  473. * @param $siteId
  474. * @return mixed
  475. */
  476. public function connection($siteId)
  477. {
  478. $site = DB::connection('template')
  479. ->table('template_library_project_config')
  480. ->where('site_id', $siteId)->first();
  481. $config = [
  482. 'connection_name' => sprintf('connection_name_%s', $site->site_id),
  483. 'host' => $site->ip,
  484. 'port' => '3306',
  485. 'database' => $site->database,
  486. 'username' => $site->username,
  487. 'password' => $site->password,
  488. ];
  489. config_connection($config);
  490. return $config['connection_name'];
  491. }
  492. /**
  493. * 根据父级id查找子级数据(二维数组)
  494. * @param $array
  495. * @param $siteId
  496. * @return array
  497. */
  498. public function recursion($array, $siteId)
  499. {
  500. $output = [];
  501. foreach ($array as $value) {
  502. if (!empty($value->id)) {
  503. $list = DB::connection($this->connection($siteId))
  504. ->table('content')
  505. ->where('parent_id', $value->id)->get();
  506. $output [] = $value;
  507. $output = array_merge($output, $this->recursion($list, $siteId));
  508. }
  509. }
  510. return $output;
  511. }
  512. /**
  513. * 获取项目环境
  514. * @param $siteId
  515. * @return array
  516. */
  517. public function getSettingList($siteId)
  518. {
  519. $siteInfo = DB::connection('template')
  520. ->table('template_library_project_config')
  521. ->where('site_id', $siteId)
  522. ->select('id', 'cn_title', 'en_title', 'site_logo', 'domain', 'brand')->first();
  523. $siteInfo->id = $siteId;
  524. $setting = $this->getLanguage($siteId);
  525. return [$siteInfo, $setting];
  526. }
  527. /**
  528. * 采用递归将数据列表转换成树
  529. * @param array $dataArr 数据列表
  530. * @param int $rootId 根节点ID
  531. * @param string $pkName 主键名
  532. * @param string $pIdName 父节点id名
  533. * @param string $childName 子节点名称
  534. * @return array
  535. */
  536. public function listToTreeRecursive($dataArr, $rootId = 0, $pkName = 'id', $pIdName = 'parent_id', $childName = 'children')
  537. {
  538. $arr = [];
  539. foreach ($dataArr as $sorData) {
  540. if ($sorData[$pIdName] == $rootId) {
  541. $children = $this->listToTreeRecursive($dataArr, $sorData[$pkName]);
  542. if ($children) {
  543. $sorData[$childName] = $children;
  544. }
  545. $arr[] = $sorData;
  546. }
  547. }
  548. return $arr;
  549. }
  550. }