WME Place Interface Enhancements

Enhancements to various Place interfaces

目前為 2017-01-09 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name WME Place Interface Enhancements
  3. // @namespace https://greasyfork.org/users/30701-justins83-waze
  4. // @version 0.3.0
  5. // @description Enhancements to various Place interfaces
  6. // @include https://www.waze.com/editor/*
  7. // @include https://www.waze.com/*/editor/*
  8. // @include https://beta.waze.com/*
  9. // @exclude https://www.waze.com/user/editor*
  10. // @author JustinS83
  11. // @grant none
  12. // @require https://greasyfork.org/scripts/24851-wazewrap/code/WazeWrap.js
  13. // @license GPLv3
  14. // ==/UserScript==
  15.  
  16. (function() {
  17. 'use strict';
  18.  
  19. var settings = {};
  20.  
  21. // Your code here...
  22. function bootstrap(tries) {
  23. tries = tries || 1;
  24.  
  25. if (window.W &&
  26. window.W.map &&
  27. window.W.model &&
  28. $) {
  29. init();
  30. } else if (tries < 1000) {
  31. setTimeout(function () {bootstrap(tries++);}, 200);
  32. }
  33. }
  34.  
  35. bootstrap();
  36.  
  37. function init(){
  38. var $section = $("<div>", {style:"padding:8px 16px", id:"WMEPIESettings"});
  39. $section.html([
  40. '<h4><b>WME Place Interface Enhancements</b></h4>',
  41. '<div class="controls-container" id="divAreaPlaceSizeControls">',
  42. '<div id="divShowAreaPlaceSize" class="controls-container"><input type="checkbox" id="_cbShowAreaPlaceSize" class="pieSettingsCheckbox" /><label for="_cbShowAreaPlaceSize">Show area Place size</label></div>',
  43. '<div id="divShowAreaPlaceSizeImperial"class="controls-container" style="padding-left:30px;"><input type="checkbox" id="_cbShowAreaPlaceSizeImperial" class="pieSettingsCheckbox" disabled /><label for ="_cbShowAreaPlaceSizeImperial"> Show imperial </label></div>',
  44. '<div id="divShowAreaPlaceSizeMetric" class="controls-container" style="padding-left:30px;"><input type="checkbox" id="_cbShowAreaPlaceSizeMetric" class="pieSettingsCheckbox" disabled /><label for ="_cbShowAreaPlaceSizeMetric"> Show metric</label></div>',
  45. '</div>',
  46. '<div class="controls-container" id="divShowLockButtonsRPP"><input type="checkbox" id="_cbShowLockButtonsRPP" class="pieSettingsCheckbox" /><label for="_cbShowLockButtonsRPP">Show lock buttons for RPPs</label></div>',
  47. '<div class="controls-container" id="divPlaceMenuCustomization">',
  48. '<b>Place Menu Customization</b></br>',
  49. buildItemOption(1),
  50. buildItemOption(2),
  51. buildItemOption(3),
  52. buildItemOption(4),
  53. buildItemOption(5),
  54. buildItemOption(6),
  55. buildItemOption(7),
  56. buildItemOption(8),
  57. buildItemOption(9),
  58. buildItemOption(10),
  59. buildItemOption(11),
  60. '</div>'
  61.  
  62. ].join(' '));
  63. new WazeWrap.Interface.Tab('PIE', $section.html(), init2);
  64. }
  65.  
  66. function buildNewPlaceList(){
  67. /*<div class="drawing-controls">
  68. <span class="drawing-control polygon secondary-control" title="Place (area)"></span>
  69. <span class="drawing-control main-control point" title="Place (point)"></span>
  70. </div>
  71. $('#pieItem1')[0].options[$('#pieItem1')[0].selectedIndex].innerHTML //get selected option text
  72. */
  73. }
  74.  
  75. function init2(){
  76. //First load settings
  77. loadSettings();
  78. //Second set up event handlers
  79. $('#_cbShowAreaPlaceSize').change(function() {
  80. if(this.checked) {
  81. attachPlaceSizeHandlers();
  82. updatePlaceSizeDisplay();
  83. $('#_cbShowAreaPlaceSizeImperial')[0].disabled = false;
  84. $('#_cbShowAreaPlaceSizeMetric')[0].disabled = false;
  85. }
  86. else
  87. {
  88. removePlaceSizeHandlers();
  89. $('#AreaSize').remove();
  90. $('#_cbShowAreaPlaceSizeImperial')[0].disabled = true;
  91. $('#_cbShowAreaPlaceSizeMetric')[0].disabled = true;
  92. }
  93. });
  94.  
  95. $('#_cbShowLockButtonsRPP').change(function() {
  96. if(this.checked) {
  97. attachRPPLockButtonHandlers();
  98. }
  99. else
  100. {
  101. $('#RPPOptionPlaceLockButtonsContainer').remove();
  102. W.selectionManager.events.unregister("selectionchanged", null, addLockButtons);
  103. W.model.actionManager.events.unregister("afterundoaction",null, addLockButtons);
  104. W.model.actionManager.events.unregister("afterclearactions",null, addLockButtons);
  105. W.model.actionManager.events.unregister("afteraction",null, addLockButtons);
  106. }
  107. });
  108.  
  109. //Third load settings to interface
  110. setChecked('_cbShowAreaPlaceSize', settings.ShowAreaPlaceSize);
  111. setChecked('_cbShowAreaPlaceSizeImperial', settings.ShowAreaPlaceSizeImperial);
  112. setChecked('_cbShowAreaPlaceSizeMetric', settings.ShowAreaPlaceSizeMetric);
  113. setChecked('_cbShowLockButtonsRPP', settings.ShowLockButtonsRPP);
  114. if(settings.ShowAreaPlaceSize){
  115. $('#_cbShowAreaPlaceSizeImperial')[0].disabled = false;
  116. $('#_cbShowAreaPlaceSizeMetric')[0].disabled = false;
  117. attachPlaceSizeHandlers();
  118. }
  119.  
  120. if(settings.ShowLockButtonsRPP)
  121. attachRPPLockButtonHandlers();
  122.  
  123. $('.pieSettingsCheckbox').change(function() {
  124. var settingName = $(this)[0].id.substr(3);
  125. settings[settingName] = this.checked;
  126. saveSettings();
  127. });
  128.  
  129. //Whenever a Place item is changed, read the settings and save to localStorage
  130. $('[id^="pieItem"]').change(function(){
  131. for(i=0;i<11;i++){
  132. settings.NewPlacesList[i] = $('#pieItem'+(i+1))[0].value;
  133. }
  134. saveSettings();
  135. });
  136.  
  137. //Load settings into Place Customization list options
  138. for(i=0; i<11;i++)
  139. $('#pieItem'+(i+1))[0].value = settings.NewPlacesList[i];
  140. }
  141.  
  142. function buildItemOption(itemNumber){
  143. var $section = $("<div>", {style:"padding:8px 16px", id:"piePlaceCat" + itemNumber});
  144. $section.html([
  145. 'Item ',
  146. itemNumber,
  147. buildItemList(itemNumber),
  148. '</br>'
  149. ].join(' '));
  150.  
  151. return $section.html();
  152. }
  153.  
  154. function buildItemList(itemNumber){
  155. /*var yourSelect = document.getElementById( "your-select-id" );
  156. alert( yourSelect.options[ yourSelect.selectedIndex ].value )*/
  157. var $places = $("<div>");
  158. $places.html([
  159. '<select id="pieItem' + itemNumber + '">',
  160. '<option value="CAR_SERVICES" style="font-weight:bold;">Car Services</option>',
  161. '<option value="GAS_STATION">Gas Station</option>',
  162. '<option value="GARAGE_AUTOMOTIVE_SHOP">Garage / Automotive Shop</option>',
  163. '<option value="CAR_WASH">Car Wash</option>',
  164. '<option value="CHARGING_STATION">Charging Station</option>',
  165. '<option value="TRANSPORTATION" style="font-weight:bold;">Transportation</option>',
  166. '<option value="AIRPORT">Airport</option>',
  167. '<option value="BUS_STATION">Bus Station</option>',
  168. '<option value="FERRY_PIER">Ferry / Pier</option>',
  169. '<option value="SEAPORT_MARINA_HARBOR">Seaport / Marina / Harbor</option>',
  170. '<option value="SUBWAY_STATION">Subway Station</option>',
  171. '<option value="TRAIN_STATION">Train Station</option>',
  172. '<option value="BRIDGE">Bridge</option>',
  173. '<option value="TUNNEL">Tunnel</option>',
  174. '<option value="TAXI_STATION">Taxi Station</option>',
  175. '<option value="JUNCTION_INTERCHANGE">Junction / Interchange</option>',
  176. '<option value="PROFESSIONAL_AND_PUBLIC" style="font-weight:bold;">Professional and public</option>',
  177. '<option value="COLLEGE_UNIVERSITY">College / University</option>',
  178. '<option value="SCHOOL">School</option>',
  179. '<option value="CONVENTIONS_EVENT_CENTER">Conventions / Event Center</option>',
  180. '<option value="GOVERNMENT">Government</option>',
  181. '<option value="LIBRARY">Library</option>',
  182. '<option value="CITY_HALL">City Hall</option>',
  183. '<option value="ORGANIZATION_OR_ASSOCIATION">Organization or Association</option>',
  184. '<option value="COURTHOUSE">Courthouse</option>',
  185. '<option value="CEMETERY">Cemetery</option>',
  186. '<option value="FIRE_DEPARTMENT">Fire Department</option>',
  187. '<option value="POLICE_STATION">Police Station</option>',
  188. '<option value="MILITARY">Military</option>',
  189. '<option value="HOSPITAL_MEDICAL_CARE">Hospital / Medical Care</option>',
  190. '<option value="OFFICES">Offices</option>',
  191. '<option value="POST_OFFICE">Post Office</option>',
  192. '<option value="RELIGIOUS_CENTER">Religious Center</option>',
  193. '<option value="KINDERGARDEN">Kindergarden</option>',
  194. '<option value="FACTORY_INDUSTRIAL">Factory / Industrial</option>',
  195. '<option value="EMBASSY_CONSULATE">Embassy / Consulate</option>',
  196. '<option value="INFORMATION_POINT">Information Point</option>',
  197. '<option value="EMERGENCY_SHELTER">Emergency Shelter</option>',
  198. '<option value="SHOPPING_AND_SERVICES" style="font-weight:bold;">Shopping and services</option>',
  199. '<option value="ARTS_AND_CRAFTS">Arts & Crafts</option>',
  200. '<option value="BANK_FINANCIAL">Bank / Financial</option>',
  201. '<option value="SPORTING_GOODS">Sporting Goods</option>',
  202. '<option value="BOOKSTORE">Bookstore</option>',
  203. '<option value="PHOTOGRAPHY">Photography</option>',
  204. '<option value="CAR_DEALERSHIP">Car Dealership</option>',
  205. '<option value="FASHION_AND_CLOTHING">Fashion and Clothing</option>',
  206. '<option value="CONVENIENCE_STORE">Convenience Store</option>',
  207. '<option value="PERSONAL_CARE">Personal Care</option>',
  208. '<option value="DEPARTMENT_STORE">Department Store</option>',
  209. '<option value="PHARMACY">Pharmacy</option>',
  210. '<option value="ELECTRONICS">Electronics</option>',
  211. '<option value="FLOWERS">Flowers</option>',
  212. '<option value="FURNITURE_HOME_STORE">Furniture / Home Store</option>',
  213. '<option value="GIFTS">Gifts</option>',
  214. '<option value="GYM_FITNESS">Gym / Fitness</option>',
  215. '<option value="SWIMMING_POOL">Swimming Pool</option>',
  216. '<option value="HARDWARE_STORE">Hardware Store</option>',
  217. '<option value="MARKET">Market</option>',
  218. '<option value="SUPERMARKET_GROCERY">Supermarket / Grocery</option>',
  219. '<option value="JEWELRY">Jewelry</option>',
  220. '<option value="LAUNDRY_DRY_CLEAN">Laundry / Dry Clean</option>',
  221. '<option value="SHOPPING_CENTER">Shopping Center</option>',
  222. '<option value="MUSIC_STORE">Music Store</option>',
  223. '<option value="PET_STORE_VETERINARIAN_SERVICES">Pet Store / Veterinarian Services</option>',
  224. '<option value="TOY_STORE">Toy Store</option>',
  225. '<option value="TRAVEL_AGENCY">Travel Agency</option>',
  226. '<option value="ATM">ATM</option>',
  227. '<option value="CURRENCY_EXCHANGE">Currency Exchange</option>',
  228. '<option value="CAR_RENTAL">Car Rental</option>',
  229. '<option value="FOOD_AND_DRINK" style="font-weight:bold;">Food and Drink</option>',
  230. '<option value="RESTAURANT">Restaurant</option>',
  231. '<option value="BAKERY">Bakery</option>',
  232. '<option value="DESSERT">Dessert</option>',
  233. '<option value="CAFE">Cafe</option>',
  234. '<option value="FAST_FOOD">Fast Food</option>',
  235. '<option value="FOOD_COURT">Food Court</option>',
  236. '<option value="BAR">Bar</option>',
  237. '<option value="ICE_CREAM">Ice Cream</option>',
  238. '<option value="CULTURE_AND_ENTERTAINEMENT" style="font-weight:bold;">Culture & Entertainment</option>',
  239. '<option value="ART_GALLERY">Art Gallery</option>',
  240. '<option value="CASINO">Casino</option>',
  241. '<option value="CLUB">Club</option>',
  242. '<option value="TOURIST_ATTRACTION_HISTORIC_SITE">Tourist Attraction / History Site</option>',
  243. '<option value="MOVIE_THEATER">Movie Theater</option>',
  244. '<option value="MUSEUM">Museum</option>',
  245. '<option value="MUSIC_VENUE">Music Venue</option>',
  246. '<option value="PERFORMING_ARTS_VENUE">Performing Arts Venue</option>',
  247. '<option value="GAME_CLUB">Game Club</option>',
  248. '<option value="STADIUM_ARENA">Stadium / Arena</option>',
  249. '<option value="THEME_PARK">Theme Park</option>',
  250. '<option value="ZOO_AQUARIUM">Zoo / Aquarium</option>',
  251. '<option value="RACING_TRACK">Racing Track</option>',
  252. '<option value="THEATER">Theater</option>',
  253. '<option value="OTHER" style="font-weight:bold;">Other</option>',
  254. '<option value="CONSTRUCTION_SITE">Construction Site</option>',
  255. '<option value="LODGING" style="font-weight:bold;">Lodging</option>',
  256. '<option value="HOTEL">Hotel</option>',
  257. '<option value="HOSTEL">Hostel</option>',
  258. '<option value="CAMPING_TRAILER_PARK">Camping / Trailer Park</option>',
  259. '<option value="COTTAGE_CABIN">Cottage / Cabin</option>',
  260. '<option value="BED_AND_BREAKFAST">Bed & Breakfast</option>',
  261. '<option value="OUTDOORS" style="font-weight:bold;">Outdoors</option>',
  262. '<option value="PARK">Park</option>',
  263. '<option value="PLAYGROUND">Playground</option>',
  264. '<option value="BEACH">Beach</option>',
  265. '<option value="SPORTS_COURT">Sports Court</option>',
  266. '<option value="GOLF_COURSE">Golf Course</option>',
  267. '<option value="PLAZA">Plaza</option>',
  268. '<option value="PROMENADE">Promenade</option>',
  269. '<option value="POOL">Pool</option>',
  270. '<option value="SCENIC_LOOKOUT_VIEWPOINT">Scenic Lookout / Viewpoint</option>',
  271. '<option value="SKI_AREA">Ski Area</option>',
  272. '<option value="NATURAL_FEATURES" style="font-weight:bold;">Natural Features</option>',
  273. '<option value="ISLAND">Island</option>',
  274. '<option value="SEA_LAKE_POOL">Sea / Lake / Pool</option>',
  275. '<option value="RIVER_STREAM">River / Stream</option>',
  276. '<option value="FOREST_GROVE">Forest / Grove</option>',
  277. '<option value="FARM">Farm</option>',
  278. '<option value="CANAL">Canal</option>',
  279. '<option value="SWAMP_MARSH">Swamp / Marsh</option>',
  280. '<option value="DAM">Dam</option>',
  281. '<option value="PARKING_LOT" style="font-weight:bold;">Parking Lot</option>',
  282. '<option value="RESIDENCE_HOME" style="font-weight:bold;">Residential</option>',
  283. '</select>'
  284. ].join(' '));
  285.  
  286. return $places.html();
  287. }
  288.  
  289. function attachRPPLockButtonHandlers(){
  290. $('#RPPOptionPlaceLockButtonsContainer').remove();
  291. W.selectionManager.events.register("selectionchanged", null, addLockButtons);
  292. W.model.actionManager.events.register("afterundoaction",null, addLockButtons);
  293. W.model.actionManager.events.register("afterclearactions",null, addLockButtons);
  294. W.model.actionManager.events.register("afteraction",null, addLockButtons);
  295. }
  296.  
  297. function attachPlaceSizeHandlers(){
  298. W.selectionManager.events.register("selectionchanged", null, updatePlaceSizeDisplay);
  299. W.model.actionManager.events.register("afteraction",null, updatePlaceSizeDisplay);
  300. W.model.actionManager.events.register("afterundoaction",null, updatePlaceSizeDisplay);
  301. W.model.actionManager.events.register("afterclearactions",null, updatePlaceSizeDisplay);
  302. W.model.actionManager.events.register("noActions",null, noActions);
  303. updatePlaceSizeDisplay();
  304. }
  305.  
  306. function removePlaceSizeHandlers(){
  307. W.selectionManager.events.unregister("selectionchanged", null, updatePlaceSizeDisplay);
  308. W.model.actionManager.events.unregister("afteraction",null, updatePlaceSizeDisplay);
  309. W.model.actionManager.events.unregister("afterundoaction",null, updatePlaceSizeDisplay);
  310. W.model.actionManager.events.unregister("afterclearactions",null, updatePlaceSizeDisplay);
  311. W.model.actionManager.events.unregister("noActions",null, noActions);
  312. }
  313.  
  314. function isChecked(checkboxId) {
  315. return $('#' + checkboxId).is(':checked');
  316. }
  317.  
  318. function setChecked(checkboxId, checked) {
  319. $('#' + checkboxId).prop('checked', checked);
  320. }
  321.  
  322. function noActions(){
  323. setTimeout(updatePlaceSizeDisplay, 100 ); //have to put in a delay for when the user uses undo to clear all actions - WME updates on top of my changes otherwise.
  324. }
  325.  
  326. function updatePlaceSizeDisplay(){
  327. var count = W.selectionManager.selectedItems.length;
  328. var metersArea = 0;
  329. var bold = false;
  330. if(count === 1){
  331. var venue = W.selectionManager.selectedItems[0];
  332. var isArea = venue.geometry.toString().match(/^POLYGON/);
  333. //var isPoint = venue.geometry.toString().match(/^POINT/);
  334.  
  335. if(venue.model.type === "venue" && isArea){
  336. if($('#AreaSize'))
  337. $('#AreaSize').remove();
  338. metersArea = W.selectionManager.selectedItems[0].model.geometry.getGeodesicArea(W.map.getProjectionObject());
  339.  
  340. if(metersArea > 0 && isArea){
  341. var ftArea = Math.round(metersArea * 10.76391 *100)/100;
  342.  
  343. var list = $('#landmark-edit-general > ul')[0];
  344. var newList = document.createElement("UL");
  345. newList.id = "AreaSize";
  346.  
  347. var newItem = document.createElement("LI");
  348. if(isChecked("_cbShowAreaPlaceSizeMetric")){
  349. newItem.innerHTML = "Area: " + metersArea.toFixed(2) + " m<sup>2</sup>";
  350. newList.append(newItem);
  351. }
  352.  
  353. if(isChecked("_cbShowAreaPlaceSizeImperial")){
  354. newItem = document.createElement("LI");
  355. newItem.innerHTML = "Area: " + ftArea.toFixed(2) + " ft<sup>2</sup>";
  356. newList.append(newItem);
  357. }
  358. if(metersArea < 500){
  359. newItem = document.createElement("LI");
  360. newItem.innerHTML = "<span style='color:red; font-weight:bold;'>Places smaller than 500 m<sup>2</sup>/5382 ft<sup>2</sup> will not show in the client</span>";
  361. newList.append(newItem);
  362. }
  363. list.before(newList);
  364.  
  365. $('#AreaSize').addClass("list-unstyled");
  366. $('#AreaSize').addClass("additional-attributes");
  367. }
  368. }
  369. }
  370. }
  371.  
  372. function loadSettings() {
  373. var loadedSettings = $.parseJSON(localStorage.getItem("WMEPIE_Settings"));
  374. var defaultSettings = {
  375. ShowAreaPlaceSize: false,
  376. ShowAreaPlaceSizeImperial: false,
  377. ShowAreaPlaceSizeMetric: false,
  378. ShowLockButtonsRPP: true,
  379. NewPlacesList: W.Config.venues.categories.clone()
  380. };
  381. settings = loadedSettings ? loadedSettings : defaultSettings;
  382. for (var prop in defaultSettings) {
  383. if (!settings.hasOwnProperty(prop))
  384. settings[prop] = defaultSettings[prop];
  385. }
  386.  
  387. if(settings.ShowAreaPlaceSizeImperial === false && settings.ShowAreaPlaceSizeMetric === false)
  388. if(Waze.prefs.attributes.isImperial)
  389. settings.ShowAreaPlaceSizeImperial = true;
  390. else
  391. settings.ShowAreaPlaceSizeMetric = true;
  392. }
  393.  
  394. function saveSettings() {
  395. if (localStorage) {
  396. var localsettings = {
  397. ShowAreaPlaceSize: settings.ShowAreaPlaceSize,
  398. ShowAreaPlaceSizeImperial: settings.ShowAreaPlaceSizeImperial,
  399. ShowAreaPlaceSizeMetric: settings.ShowAreaPlaceSizeMetric,
  400. ShowLockButtonsRPP: settings.ShowLockButtonsRPP,
  401. NewPlacesList: settings.NewPlacesList
  402. };
  403.  
  404. localStorage.setItem("WMEPIE_Settings", JSON.stringify(localsettings));
  405. }
  406. }
  407.  
  408. //Using the same display for lock buttons as ClickSaver (with permission from MapoMatic) - thanks MoM!
  409. function addLockButtons() {
  410. if(W.selectionManager.selectedItems.length > 0){
  411. var item = W.selectionManager.selectedItems[0];
  412. var isRPP = (item.model.type === "venue" && item.model.attributes.residential === true);
  413.  
  414. if(isRPP){
  415. console.log("adding!!!");
  416. var attr = item.model.attributes;
  417. var autoRank = attr.rank;
  418. var manualRank = attr.lockRank;
  419. var firstManualRank = manualRank;
  420. var userRank = WazeWrap.User.Rank() - 1;
  421. var maxAutoRank = autoRank;
  422. var disabled = false;
  423.  
  424. var $div = $('#RPPOptionPlaceLockButtonsContainer');
  425. $div.remove();
  426. $div = $('<div>',{id:'RPPOptionPlaceLockButtonsContainer',style:'margin-bottom:5px;'});
  427. $div.append('<label class="control-label">Lock</label>');
  428. var btnInfos = [];
  429.  
  430. for(var iBtn=0;iBtn<=6;iBtn++){btnInfos.push({r:iBtn,val:iBtn});}
  431. btnInfos.forEach(function(btnInfo){
  432. var selected = (btnInfo.val === manualRank);
  433. disabled = userRank < btnInfo.val;
  434. if (btnInfo.val !== 6) {
  435. $div.append(
  436. $('<div>', {
  437. class:'btn btn-lh' + (selected ? ' btn-lh-selected':'') + (btnInfo.r < 6 & (userRank < btnInfo.r || disabled) ? ' disabled' : '')
  438. })
  439. .text(btnInfo.hasOwnProperty('title') ? btnInfo.title : btnInfo.r + 1)
  440. .data('val',btnInfo.hasOwnProperty('val') ? btnInfo.val : btnInfo.r + 1)
  441. .hover(function() {})
  442. .click(function() {
  443. if((userRank >= $(this).data('val')) && (btnInfo.r < 6)) {
  444. W.model.actionManager.add(new UpdateObject(item.model,{lockRank:($(this).data('val'))}));
  445. addLockButtons();
  446. }
  447. })
  448. );
  449. }
  450. });
  451. $('#landmark-edit-general > div').after($div);
  452. }
  453. }
  454. }
  455.  
  456. function listPlaces(){
  457. var category = "";
  458. for(i=0; i<W.Config.venues.categories.length; i++){
  459. category = W.Config.venues.categories[i];
  460. console.log(category + " Main");
  461. var subCategories = W.Config.venues.subcategories[category];
  462. for(var j=0; j<subCategories.length;j++){
  463. console.log(subCategories[j]);
  464. }
  465. }
  466. }
  467. })();