You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

GitBlit.java 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754
  1. /*
  2. * Copyright 2013 gitblit.com.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.gitblit;
  17. import java.io.File;
  18. import java.util.Collection;
  19. import java.util.Date;
  20. import java.util.List;
  21. import java.util.Map;
  22. import java.util.TimeZone;
  23. import javax.servlet.http.HttpServletRequest;
  24. import javax.servlet.http.HttpServletResponse;
  25. import org.eclipse.jgit.lib.Repository;
  26. import com.gitblit.Constants.FederationRequest;
  27. import com.gitblit.Constants.FederationToken;
  28. import com.gitblit.manager.IAuthenticationManager;
  29. import com.gitblit.manager.IFederationManager;
  30. import com.gitblit.manager.IGitblitManager;
  31. import com.gitblit.manager.INotificationManager;
  32. import com.gitblit.manager.IProjectManager;
  33. import com.gitblit.manager.IRepositoryManager;
  34. import com.gitblit.manager.IRuntimeManager;
  35. import com.gitblit.manager.IUserManager;
  36. import com.gitblit.models.FederationModel;
  37. import com.gitblit.models.FederationProposal;
  38. import com.gitblit.models.FederationSet;
  39. import com.gitblit.models.ForkModel;
  40. import com.gitblit.models.GitClientApplication;
  41. import com.gitblit.models.Metric;
  42. import com.gitblit.models.ProjectModel;
  43. import com.gitblit.models.RegistrantAccessPermission;
  44. import com.gitblit.models.RepositoryModel;
  45. import com.gitblit.models.RepositoryUrl;
  46. import com.gitblit.models.SearchResult;
  47. import com.gitblit.models.ServerSettings;
  48. import com.gitblit.models.ServerStatus;
  49. import com.gitblit.models.TeamModel;
  50. import com.gitblit.models.UserModel;
  51. /**
  52. * GitBlit is an aggregate interface delegate. It implements all the manager
  53. * interfaces and delegates all methods calls to the actual manager implementations.
  54. * It's primary purpose is to provide complete management control to the git
  55. * upload and receive pack functions.
  56. *
  57. * @author James Moger
  58. *
  59. */
  60. public class GitBlit implements IRuntimeManager,
  61. INotificationManager,
  62. IUserManager,
  63. IAuthenticationManager,
  64. IRepositoryManager,
  65. IProjectManager,
  66. IGitblitManager,
  67. IFederationManager {
  68. private final IRuntimeManager runtimeManager;
  69. private final INotificationManager notificationManager;
  70. private final IUserManager userManager;
  71. private final IAuthenticationManager authenticationManager;
  72. private final IRepositoryManager repositoryManager;
  73. private final IProjectManager projectManager;
  74. private final IGitblitManager gitblitManager;
  75. private final IFederationManager federationManager;
  76. public GitBlit(
  77. IRuntimeManager runtimeManager,
  78. INotificationManager notificationManager,
  79. IUserManager userManager,
  80. IAuthenticationManager authenticationManager,
  81. IRepositoryManager repositoryManager,
  82. IProjectManager projectManager,
  83. IGitblitManager gitblitManager,
  84. IFederationManager federationManager) {
  85. this.runtimeManager = runtimeManager;
  86. this.notificationManager = notificationManager;
  87. this.userManager = userManager;
  88. this.authenticationManager = authenticationManager;
  89. this.repositoryManager = repositoryManager;
  90. this.projectManager = projectManager;
  91. this.gitblitManager = gitblitManager;
  92. this.federationManager = federationManager;
  93. }
  94. @Override
  95. public GitBlit start() {
  96. return this;
  97. }
  98. @Override
  99. public GitBlit stop() {
  100. return this;
  101. }
  102. /*
  103. * ISTOREDSETTINGS
  104. *
  105. * these methods are necessary for (nearly) seamless Groovy hook operation
  106. * after the massive refactor.
  107. */
  108. public boolean getBoolean(String key, boolean defaultValue) {
  109. return runtimeManager.getSettings().getBoolean(key, defaultValue);
  110. }
  111. public String getString(String key, String defaultValue) {
  112. return runtimeManager.getSettings().getString(key, defaultValue);
  113. }
  114. public int getInteger(String key, int defaultValue) {
  115. return runtimeManager.getSettings().getInteger(key, defaultValue);
  116. }
  117. public List<String> getStrings(String key) {
  118. return runtimeManager.getSettings().getStrings(key);
  119. }
  120. /*
  121. * RUNTIME MANAGER
  122. */
  123. @Override
  124. public File getBaseFolder() {
  125. return runtimeManager.getBaseFolder();
  126. }
  127. @Override
  128. public void setBaseFolder(File folder) {
  129. runtimeManager.setBaseFolder(folder);
  130. }
  131. @Override
  132. public Date getBootDate() {
  133. return runtimeManager.getBootDate();
  134. }
  135. @Override
  136. public ServerSettings getSettingsModel() {
  137. return runtimeManager.getSettingsModel();
  138. }
  139. @Override
  140. public boolean isServingRepositories() {
  141. return runtimeManager.isServingRepositories();
  142. }
  143. @Override
  144. public TimeZone getTimezone() {
  145. return runtimeManager.getTimezone();
  146. }
  147. @Override
  148. public boolean isDebugMode() {
  149. return runtimeManager.isDebugMode();
  150. }
  151. @Override
  152. public File getFileOrFolder(String key, String defaultFileOrFolder) {
  153. return runtimeManager.getFileOrFolder(key, defaultFileOrFolder);
  154. }
  155. @Override
  156. public File getFileOrFolder(String fileOrFolder) {
  157. return runtimeManager.getFileOrFolder(fileOrFolder);
  158. }
  159. @Override
  160. public IStoredSettings getSettings() {
  161. return runtimeManager.getSettings();
  162. }
  163. @Override
  164. public boolean updateSettings(Map<String, String> updatedSettings) {
  165. return runtimeManager.updateSettings(updatedSettings);
  166. }
  167. @Override
  168. public ServerStatus getStatus() {
  169. return runtimeManager.getStatus();
  170. }
  171. /*
  172. * NOTIFICATION MANAGER
  173. */
  174. @Override
  175. public void sendMailToAdministrators(String subject, String message) {
  176. notificationManager.sendMailToAdministrators(subject, message);
  177. }
  178. @Override
  179. public void sendMail(String subject, String message, Collection<String> toAddresses) {
  180. notificationManager.sendMail(subject, message, toAddresses);
  181. }
  182. @Override
  183. public void sendMail(String subject, String message, String... toAddresses) {
  184. notificationManager.sendMail(subject, message, toAddresses);
  185. }
  186. @Override
  187. public void sendHtmlMail(String subject, String message, Collection<String> toAddresses) {
  188. notificationManager.sendHtmlMail(subject, message, toAddresses);
  189. }
  190. @Override
  191. public void sendHtmlMail(String subject, String message, String... toAddresses) {
  192. notificationManager.sendHtmlMail(subject, message, toAddresses);
  193. }
  194. /*
  195. * SESSION MANAGER
  196. */
  197. @Override
  198. public UserModel authenticate(String username, char[] password) {
  199. return authenticationManager.authenticate(username, password);
  200. }
  201. @Override
  202. public UserModel authenticate(HttpServletRequest httpRequest) {
  203. return authenticationManager.authenticate(httpRequest, false);
  204. }
  205. @Override
  206. public UserModel authenticate(HttpServletRequest httpRequest, boolean requiresCertificate) {
  207. return authenticationManager.authenticate(httpRequest, requiresCertificate);
  208. }
  209. @Override
  210. public void setCookie(HttpServletResponse response, UserModel user) {
  211. authenticationManager.setCookie(response, user);
  212. }
  213. @Override
  214. public void logout(HttpServletResponse response, UserModel user) {
  215. authenticationManager.logout(response, user);
  216. }
  217. @Override
  218. public boolean supportsCredentialChanges(UserModel user) {
  219. return authenticationManager.supportsCredentialChanges(user);
  220. }
  221. @Override
  222. public boolean supportsDisplayNameChanges(UserModel user) {
  223. return authenticationManager.supportsDisplayNameChanges(user);
  224. }
  225. @Override
  226. public boolean supportsEmailAddressChanges(UserModel user) {
  227. return authenticationManager.supportsEmailAddressChanges(user);
  228. }
  229. @Override
  230. public boolean supportsTeamMembershipChanges(UserModel user) {
  231. return authenticationManager.supportsTeamMembershipChanges(user);
  232. }
  233. @Override
  234. public boolean supportsTeamMembershipChanges(TeamModel team) {
  235. return authenticationManager.supportsTeamMembershipChanges(team);
  236. }
  237. /*
  238. * USER MANAGER
  239. */
  240. @Override
  241. public void setup(IRuntimeManager runtimeManager) {
  242. }
  243. @Override
  244. public List<String> getAllUsernames() {
  245. return userManager.getAllUsernames();
  246. }
  247. @Override
  248. public List<UserModel> getAllUsers() {
  249. return userManager.getAllUsers();
  250. }
  251. @Override
  252. public boolean deleteUser(String username) {
  253. return userManager.deleteUser(username);
  254. }
  255. @Override
  256. public UserModel getUserModel(String username) {
  257. return userManager.getUserModel(username);
  258. }
  259. @Override
  260. public List<TeamModel> getAllTeams() {
  261. return userManager.getAllTeams();
  262. }
  263. @Override
  264. public TeamModel getTeamModel(String teamname) {
  265. return userManager.getTeamModel(teamname);
  266. }
  267. @Override
  268. public String getCookie(UserModel model) {
  269. return userManager.getCookie(model);
  270. }
  271. @Override
  272. public UserModel getUserModel(char[] cookie) {
  273. return userManager.getUserModel(cookie);
  274. }
  275. @Override
  276. public boolean updateUserModel(UserModel model) {
  277. return userManager.updateUserModel(model);
  278. }
  279. @Override
  280. public boolean updateUserModels(Collection<UserModel> models) {
  281. return userManager.updateUserModels(models);
  282. }
  283. @Override
  284. public boolean updateUserModel(String username, UserModel model) {
  285. return userManager.updateUserModel(username, model);
  286. }
  287. @Override
  288. public boolean deleteUserModel(UserModel model) {
  289. return userManager.deleteUserModel(model);
  290. }
  291. @Override
  292. public List<String> getAllTeamNames() {
  293. return userManager.getAllTeamNames();
  294. }
  295. @Override
  296. public List<String> getTeamNamesForRepositoryRole(String role) {
  297. return userManager.getTeamNamesForRepositoryRole(role);
  298. }
  299. @Override
  300. public boolean updateTeamModel(TeamModel model) {
  301. return userManager.updateTeamModel(model);
  302. }
  303. @Override
  304. public boolean updateTeamModels(Collection<TeamModel> models) {
  305. return userManager.updateTeamModels(models);
  306. }
  307. @Override
  308. public boolean updateTeamModel(String teamname, TeamModel model) {
  309. return userManager.updateTeamModel(teamname, model);
  310. }
  311. @Override
  312. public boolean deleteTeamModel(TeamModel model) {
  313. return userManager.deleteTeamModel(model);
  314. }
  315. @Override
  316. public List<String> getUsernamesForRepositoryRole(String role) {
  317. return userManager.getUsernamesForRepositoryRole(role);
  318. }
  319. @Override
  320. public boolean renameRepositoryRole(String oldRole, String newRole) {
  321. return userManager.renameRepositoryRole(oldRole, newRole);
  322. }
  323. @Override
  324. public boolean deleteRepositoryRole(String role) {
  325. return userManager.deleteRepositoryRole(role);
  326. }
  327. @Override
  328. public boolean deleteTeam(String teamname) {
  329. return userManager.deleteTeam(teamname);
  330. }
  331. /*
  332. * REPOSITORY MANAGER
  333. */
  334. @Override
  335. public Date getLastActivityDate() {
  336. return repositoryManager.getLastActivityDate();
  337. }
  338. @Override
  339. public File getRepositoriesFolder() {
  340. return repositoryManager.getRepositoriesFolder();
  341. }
  342. @Override
  343. public File getHooksFolder() {
  344. return repositoryManager.getHooksFolder();
  345. }
  346. @Override
  347. public File getGrapesFolder() {
  348. return repositoryManager.getGrapesFolder();
  349. }
  350. @Override
  351. public List<RegistrantAccessPermission> getUserAccessPermissions(UserModel user) {
  352. return repositoryManager.getUserAccessPermissions(user);
  353. }
  354. @Override
  355. public List<RegistrantAccessPermission> getUserAccessPermissions(RepositoryModel repository) {
  356. return repositoryManager.getUserAccessPermissions(repository);
  357. }
  358. @Override
  359. public boolean setUserAccessPermissions(RepositoryModel repository, Collection<RegistrantAccessPermission> permissions) {
  360. return repositoryManager.setUserAccessPermissions(repository, permissions);
  361. }
  362. @Override
  363. public List<String> getRepositoryUsers(RepositoryModel repository) {
  364. return repositoryManager.getRepositoryUsers(repository);
  365. }
  366. @Override
  367. public List<RegistrantAccessPermission> getTeamAccessPermissions(RepositoryModel repository) {
  368. return repositoryManager.getTeamAccessPermissions(repository);
  369. }
  370. @Override
  371. public boolean setTeamAccessPermissions(RepositoryModel repository, Collection<RegistrantAccessPermission> permissions) {
  372. return repositoryManager.setTeamAccessPermissions(repository, permissions);
  373. }
  374. @Override
  375. public List<String> getRepositoryTeams(RepositoryModel repository) {
  376. return repositoryManager.getRepositoryTeams(repository);
  377. }
  378. @Override
  379. public void addToCachedRepositoryList(RepositoryModel model) {
  380. repositoryManager.addToCachedRepositoryList(model);
  381. }
  382. @Override
  383. public void resetRepositoryListCache() {
  384. repositoryManager.resetRepositoryListCache();
  385. }
  386. @Override
  387. public List<String> getRepositoryList() {
  388. return repositoryManager.getRepositoryList();
  389. }
  390. @Override
  391. public Repository getRepository(String repositoryName) {
  392. return repositoryManager.getRepository(repositoryName);
  393. }
  394. @Override
  395. public Repository getRepository(String repositoryName, boolean logError) {
  396. return repositoryManager.getRepository(repositoryName, logError);
  397. }
  398. @Override
  399. public List<RepositoryModel> getRepositoryModels(UserModel user) {
  400. return repositoryManager.getRepositoryModels(user);
  401. }
  402. @Override
  403. public RepositoryModel getRepositoryModel(UserModel user, String repositoryName) {
  404. return repositoryManager.getRepositoryModel(repositoryName);
  405. }
  406. @Override
  407. public RepositoryModel getRepositoryModel(String repositoryName) {
  408. return repositoryManager.getRepositoryModel(repositoryName);
  409. }
  410. @Override
  411. public long getStarCount(RepositoryModel repository) {
  412. return repositoryManager.getStarCount(repository);
  413. }
  414. @Override
  415. public boolean hasRepository(String repositoryName) {
  416. return repositoryManager.hasRepository(repositoryName);
  417. }
  418. @Override
  419. public boolean hasRepository(String repositoryName, boolean caseSensitiveCheck) {
  420. return repositoryManager.hasRepository(repositoryName, caseSensitiveCheck);
  421. }
  422. @Override
  423. public boolean hasFork(String username, String origin) {
  424. return repositoryManager.hasFork(username, origin);
  425. }
  426. @Override
  427. public String getFork(String username, String origin) {
  428. return repositoryManager.getFork(username, origin);
  429. }
  430. @Override
  431. public ForkModel getForkNetwork(String repository) {
  432. return repositoryManager.getForkNetwork(repository);
  433. }
  434. @Override
  435. public long updateLastChangeFields(Repository r, RepositoryModel model) {
  436. return repositoryManager.updateLastChangeFields(r, model);
  437. }
  438. @Override
  439. public List<Metric> getRepositoryDefaultMetrics(RepositoryModel model, Repository repository) {
  440. return repositoryManager.getRepositoryDefaultMetrics(model, repository);
  441. }
  442. @Override
  443. public void updateRepositoryModel(String repositoryName, RepositoryModel repository,
  444. boolean isCreate) throws GitBlitException {
  445. repositoryManager.updateRepositoryModel(repositoryName, repository, isCreate);
  446. }
  447. @Override
  448. public void updateConfiguration(Repository r, RepositoryModel repository) {
  449. repositoryManager.updateConfiguration(r, repository);
  450. }
  451. @Override
  452. public boolean deleteRepositoryModel(RepositoryModel model) {
  453. return repositoryManager.deleteRepositoryModel(model);
  454. }
  455. @Override
  456. public boolean deleteRepository(String repositoryName) {
  457. return repositoryManager.deleteRepository(repositoryName);
  458. }
  459. @Override
  460. public List<String> getAllScripts() {
  461. return repositoryManager.getAllScripts();
  462. }
  463. @Override
  464. public List<String> getPreReceiveScriptsInherited(RepositoryModel repository) {
  465. return repositoryManager.getPreReceiveScriptsInherited(repository);
  466. }
  467. @Override
  468. public List<String> getPreReceiveScriptsUnused(RepositoryModel repository) {
  469. return repositoryManager.getPreReceiveScriptsUnused(repository);
  470. }
  471. @Override
  472. public List<String> getPostReceiveScriptsInherited(RepositoryModel repository) {
  473. return repositoryManager.getPostReceiveScriptsInherited(repository);
  474. }
  475. @Override
  476. public List<String> getPostReceiveScriptsUnused(RepositoryModel repository) {
  477. return repositoryManager.getPostReceiveScriptsUnused(repository);
  478. }
  479. @Override
  480. public List<SearchResult> search(String query, int page, int pageSize, List<String> repositories) {
  481. return repositoryManager.search(query, page, pageSize, repositories);
  482. }
  483. @Override
  484. public boolean isCollectingGarbage() {
  485. return repositoryManager.isCollectingGarbage();
  486. }
  487. @Override
  488. public boolean isCollectingGarbage(String repositoryName) {
  489. return repositoryManager.isCollectingGarbage(repositoryName);
  490. }
  491. /*
  492. * PROJECT MANAGER
  493. */
  494. @Override
  495. public List<ProjectModel> getProjectModels(UserModel user, boolean includeUsers) {
  496. return projectManager.getProjectModels(user, includeUsers);
  497. }
  498. @Override
  499. public ProjectModel getProjectModel(String name, UserModel user) {
  500. return projectManager.getProjectModel(name, user);
  501. }
  502. @Override
  503. public ProjectModel getProjectModel(String name) {
  504. return projectManager.getProjectModel(name);
  505. }
  506. @Override
  507. public List<ProjectModel> getProjectModels(List<RepositoryModel> repositoryModels, boolean includeUsers) {
  508. return projectManager.getProjectModels(repositoryModels, includeUsers);
  509. }
  510. /*
  511. * FEDERATION MANAGER
  512. */
  513. @Override
  514. public File getProposalsFolder() {
  515. return federationManager.getProposalsFolder();
  516. }
  517. @Override
  518. public UserModel getFederationUser() {
  519. return federationManager.getFederationUser();
  520. }
  521. @Override
  522. public boolean canFederate() {
  523. return federationManager.canFederate();
  524. }
  525. @Override
  526. public List<FederationModel> getFederationRegistrations() {
  527. return federationManager.getFederationRegistrations();
  528. }
  529. @Override
  530. public FederationModel getFederationRegistration(String url, String name) {
  531. return federationManager.getFederationRegistration(url, name);
  532. }
  533. @Override
  534. public List<FederationSet> getFederationSets(String gitblitUrl) {
  535. return federationManager.getFederationSets(gitblitUrl);
  536. }
  537. @Override
  538. public List<String> getFederationTokens() {
  539. return federationManager.getFederationTokens();
  540. }
  541. @Override
  542. public String getFederationToken(FederationToken type) {
  543. return federationManager.getFederationToken(type);
  544. }
  545. @Override
  546. public String getFederationToken(String value) {
  547. return federationManager.getFederationToken(value);
  548. }
  549. @Override
  550. public boolean validateFederationRequest(FederationRequest req, String token) {
  551. return federationManager.validateFederationRequest(req, token);
  552. }
  553. @Override
  554. public boolean acknowledgeFederationStatus(String identification, FederationModel registration) {
  555. return federationManager.acknowledgeFederationStatus(identification, registration);
  556. }
  557. @Override
  558. public List<FederationModel> getFederationResultRegistrations() {
  559. return federationManager.getFederationResultRegistrations();
  560. }
  561. @Override
  562. public boolean submitFederationProposal(FederationProposal proposal, String gitblitUrl) {
  563. return federationManager.submitFederationProposal(proposal, gitblitUrl);
  564. }
  565. @Override
  566. public List<FederationProposal> getPendingFederationProposals() {
  567. return federationManager.getPendingFederationProposals();
  568. }
  569. @Override
  570. public Map<String, RepositoryModel> getRepositories(String gitblitUrl, String token) {
  571. return federationManager.getRepositories(gitblitUrl, token);
  572. }
  573. @Override
  574. public FederationProposal createFederationProposal(String gitblitUrl, String token) {
  575. return federationManager.createFederationProposal(gitblitUrl, token);
  576. }
  577. @Override
  578. public FederationProposal getPendingFederationProposal(String token) {
  579. return federationManager.getPendingFederationProposal(token);
  580. }
  581. @Override
  582. public boolean deletePendingFederationProposal(FederationProposal proposal) {
  583. return federationManager.deletePendingFederationProposal(proposal);
  584. }
  585. /*
  586. * GITBLIT MANAGER
  587. */
  588. @Override
  589. public RepositoryModel fork(RepositoryModel repository, UserModel user) throws GitBlitException {
  590. return gitblitManager.fork(repository, user);
  591. }
  592. @Override
  593. public void updateTeamModel(String teamname, TeamModel team, boolean isCreate)
  594. throws GitBlitException {
  595. gitblitManager.updateTeamModel(teamname, team, isCreate);
  596. }
  597. @Override
  598. public void updateUserModel(String username, UserModel user, boolean isCreate)
  599. throws GitBlitException {
  600. gitblitManager.updateUserModel(username, user, isCreate);
  601. }
  602. @Override
  603. public List<RepositoryUrl> getRepositoryUrls(HttpServletRequest request, UserModel user, RepositoryModel repository) {
  604. return gitblitManager.getRepositoryUrls(request, user, repository);
  605. }
  606. @Override
  607. public Collection<GitClientApplication> getClientApplications() {
  608. return gitblitManager.getClientApplications();
  609. }
  610. }