您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Want better control of your Munzee sandbox? Here you go!
当前为
// ==UserScript== // @name Zandboxee // @namespace none // @version 2019.01.03.2313α // @description Want better control of your Munzee sandbox? Here you go! // @supportURL https://Discord.me/TheShoeStore // @author technical13 // @match https://www.munzee.com/map/* // @grant none // ==/UserScript== // jshint esversion: 6 var isDebug = false; var intVerbosity = 0; const ver = '2019.01.03.2313α'; const scriptName = 'Zandboxee v' + ver; function log( intV, strConsole, strLog, ...arrArgs ) { if ( intV === undefined ) { intV = 0; } if ( strConsole === undefined ) { strConsole = 'log'; } if ( strLog === undefined ) { strLog = '%o'; } if ( intVerbosity >= intV && ( strConsole === 'groupEnd' ) ) { console[ strConsole ](); } if ( intV === 0 || ( isDebug && intVerbosity >= intV ) ) { console[ strConsole ]( '[%i]: %s: ' + strLog, intV, scriptName, ...arrArgs ); } } function toBoolean( val ) { const arrTrue = [ undefined, null, '', true, 'true', 1, '1', 'on', 'yes' ]; val = ( typeof( val ) === 'string' ? val.toLowerCase() : val ); log( 4, 'log', 'toBoolean() is returning: %o', ( arrTrue.indexOf( val ) !== -1 ? true : false ) ); return ( arrTrue.indexOf( val ) !== -1 ? true : false ); } const intParamsStart = ( document.URL.indexOf( '?' ) + 1 ); const strParams = document.URL.substr( intParamsStart ); const arrParamSets = strParams.split( '&' ); var objParams = {}; arrParamSets.forEach( function( strParam ) { let arrParam = strParam.split( '=' ); let strParamName = ( arrParam[ 0 ].toLowerCase() || '' ); if ( strParamName === 'verbosity' ) { isDebug = true; intVerbosity = ( arrParam[ 1 ] ? ( parseInt( arrParam[ 1 ] ) < 0 ? 0 : ( parseInt( arrParam[ 1 ] ) > 9 ? 9 : parseInt( arrParam[ 1 ] ) ) ) : 9 ); } else if ( strParamName === 'debug' ) { isDebug = toBoolean( arrParam[ 1 ] ); intVerbosity = 1; } } ); log( 1, 'warn', 'Debug mode is on with verbosity level: %o', intVerbosity ); log( 1, 'groupCollapsed', 'Verbosity options: (click to expand)' ); log( 1, 'log', '\n\t1) Summary\n\t2) Parameters retrieved from URL\n\t3) Variables set\n\t4) Function returns\n\t9) ALL debugging info and this notice.' ); log( 1, 'groupEnd' ); var munzeesandboxcounter = parseInt( localStorage.munzeesandboxcounter || 0 ); var munzeesandbox = JSON.parse( localStorage.munzeesandbox || '[]' ); if ( munzeesandboxcounter !== munzeesandbox.length ) { munzeesandboxcounter = munzeesandbox.length; localStorage.setItem( 'munzeesandboxcounter', munzeesandboxcounter ); log( 1, 'error', 'munzeesandboxcounter failed sanity check!\n\tReset value to: %i', munzeesandboxcounter ); } if ( munzeesandboxcounter > 0 ) { log( 3, 'log', 'Sandbox has %i pin%s in it.', munzeesandboxcounter, ( munzeesandboxcounter === 1 ? '' : 's' ) ); } else { log( 3, 'error', 'Sandbox is empty.' ); } Function.prototype.saveSandbox = function () { localStorage.setItem( 'munzeesandbox', JSON.stringify( munzeesandbox ) ); localStorage.setItem( 'munzeesandboxcounter', munzeesandboxcounter ); } function createTableHead() { var domZandboxTableHead = document.createElement( 'thead' ); var domZandBoxTableHeadRow = document.createElement( 'tr' ); var domZandBoxTableHeadColPin = document.createElement( 'th' ); var domZandBoxTableHeadColLat = document.createElement( 'th' ); var domZandBoxTableHeadColLon = document.createElement( 'th' ); var domZandBoxTableHeadColOwn = document.createElement( 'th' ); var domZandBoxTableHeadColName = document.createElement( 'th' ); var domZandBoxTableHeadColId = document.createElement( 'th' ); var domZandBoxTableHeadColSaveAddRem = document.createElement( 'th' ); domZandBoxTableHeadColId.className = 'hidden-id'; domZandBoxTableHeadColPin.style = 'text-align: center !important; width: 50px !important;'; domZandBoxTableHeadColLat.style = 'text-align: center !important;'; domZandBoxTableHeadColLon.style = 'text-align: center !important;'; domZandBoxTableHeadColOwn.style = 'text-align: center !important;'; domZandBoxTableHeadColName.style = 'text-align: center !important;'; domZandBoxTableHeadColId.style = 'text-align: center !important; display: none;' domZandBoxTableHeadColSaveAddRem.style = 'text-align: center !important;'; domZandBoxTableHeadColPin.innerText = '#'; domZandBoxTableHeadColLat.innerText = 'Latitude'; domZandBoxTableHeadColLon.innerText = 'Longitude'; domZandBoxTableHeadColOwn.innerText = 'Own'; domZandBoxTableHeadColName.innerText = 'Name'; domZandBoxTableHeadColId.innerText = 'ID'; domZandBoxTableHeadColSaveAddRem.innerHTML = 'Save - Add/Remove'; domZandBoxTableHeadRow.append( domZandBoxTableHeadColPin ); domZandBoxTableHeadRow.append( domZandBoxTableHeadColLat ); domZandBoxTableHeadRow.append( domZandBoxTableHeadColLon ); domZandBoxTableHeadRow.append( domZandBoxTableHeadColOwn ); domZandBoxTableHeadRow.append( domZandBoxTableHeadColName ); domZandBoxTableHeadRow.append( domZandBoxTableHeadColId ); domZandBoxTableHeadRow.append( domZandBoxTableHeadColSaveAddRem ); domZandboxTableHead.append( domZandBoxTableHeadRow ); return domZandboxTableHead; } Function.prototype.removeTableRow = function ( valId ) { var intIndex = ( isNaN( valId ) ? ( valId === 'ZandboxNewRow' ? ( $( 'table#ZandboxTable tr' ).length - 2 ) : parseInt( valId.replace( 'ZandboxRow-', '' ) ) ) : valId ); if ( valId !== 'ZandboxNewRow' ) { log( 4, 'log', 'Function.prototype.removeTableRow() updating row indices.' ); $( 'table#ZandboxTable tr' ).each( function( intRow, domTR ) { if ( intRow === intIndex ) { log( 4, 'log', 'Function.prototype.removeTableRow() renaming row %i to ZandboxRemoveRow.', intRow ); domTR.id = 'ZandboxRemoveRow'; } else if ( intRow > intIndex && domTR.id !== 'ZandboxNewRow' ) { log( 4, 'log', 'Function.prototype.removeTableRow() renumbering row %i to %i.', intRow, ( intRow - 1 ) ); // Function.updateMunzee( intRow ); domTR.id = 'ZandboxRow-' + ( intRow - 1 ); domTR.cells[ 0 ].innerText = ( intRow - 1 ); } else if ( domTR.id === 'ZandboxNewRow' ) { log( 4, 'log', 'Function.prototype.removeTableRow() renumbering add munzee row to %i.', ( intRow - 1 ) ); domTR.cells[ 0 ].innerText = ( intRow - 1 ); } } ); } else { log( 4, 'log', 'Function.prototype.removeTableRow() renaming ZandboxNewRow to ZandboxRemoveRow.' ); document.getElementById( 'ZandboxNewRow' ).id = 'ZandboxRemoveRow'; } log( 4, 'log', 'Function.prototype.removeTableRow() removing row %i (%o) from table.', intIndex, valId ); $( 'tr#ZandboxRemoveRow' ).remove(); } Function.prototype.createNewMunzeeRow = function () { log( 4, 'log', 'Function.prototype.createNewMunzeeRow() creating "Add new Munzee" row for table.' ); var domZandBoxTableRow = document.createElement( 'tr' ); var domZandBoxTableRowPin = document.createElement( 'td' ); var domZandBoxTableRowLat = document.createElement( 'td' ); var domZandBoxTableRowLon = document.createElement( 'td' ); var domZandBoxTableRowOwn = document.createElement( 'td' ); var domZandBoxTableRowName = document.createElement( 'td' ); var domZandBoxTableRowId = document.createElement( 'td' ); var domZandBoxTableRowAdd = document.createElement( 'td' ); domZandBoxTableRow.id = 'ZandboxNewRow'; domZandBoxTableRowId.style = 'display: none;'; domZandBoxTableRowId.className = 'hidden-id'; var domZandBoxTextPin = document.createTextNode( munzeesandbox.length + 1 ); var domZandBoxInputLat = document.createElement( 'input' ); var domZandBoxInputLon = document.createElement( 'input' ); var domZandBoxInputOwn = document.createElement( 'input' ); var domZandBoxInputName = document.createElement( 'input' ); var domZandBoxInputId = document.createElement( 'input' ); var domZandBoxInputAdd = document.createElement( 'input' ); domZandBoxInputLat.type = 'text'; domZandBoxInputLon.type = 'text'; domZandBoxInputOwn.type = 'checkbox'; domZandBoxInputName.type = 'text'; domZandBoxInputId.type = 'number'; domZandBoxInputAdd.type = 'button'; domZandBoxInputLat.id = 'NewMunzeeLat'; domZandBoxInputLon.id = 'NewMunzeeLng'; domZandBoxInputOwn.id = 'NewMunzeeOwn'; domZandBoxInputName.id = 'NewMunzeeName'; domZandBoxInputId.id = 'NewMunzeeId'; domZandBoxInputAdd.id = 'NewMunzeeAdd'; domZandBoxInputLat.size = '25'; domZandBoxInputLon.size = '25'; domZandBoxInputName.maxlength = '33'; domZandBoxInputName.size = '35'; domZandBoxInputLat.style = 'text-align: right;'; domZandBoxInputLon.style = 'text-align: right;'; domZandBoxInputName.style = 'text-align: right;'; domZandBoxInputId.style = 'text-align: center;'; domZandBoxInputLat.placeholder = map.getCenter().lat; domZandBoxInputLon.placeholder = map.getCenter().lng; domZandBoxInputOwn.checked = true; domZandBoxInputName.placeholder = 'Quick Deploy by ' + username; domZandBoxInputId.placeholder = munzeesandbox.length.toString(); domZandBoxInputAdd.value = 'Add'; domZandBoxInputAdd.setAttribute( 'onClick', 'Function.addMunzee();'); domZandBoxTableRowPin.append( domZandBoxTextPin ); domZandBoxTableRowLat.append( domZandBoxInputLat ); domZandBoxTableRowLon.append( domZandBoxInputLon ); domZandBoxTableRowOwn.append( domZandBoxInputOwn ); domZandBoxTableRowName.append( domZandBoxInputName ); domZandBoxTableRowId.append( domZandBoxInputId ); domZandBoxTableRowAdd.append( domZandBoxInputAdd ); domZandBoxTableRow.append( domZandBoxTableRowPin ); domZandBoxTableRow.append( domZandBoxTableRowLat ); domZandBoxTableRow.append( domZandBoxTableRowLon ); domZandBoxTableRow.append( domZandBoxTableRowOwn ); domZandBoxTableRow.append( domZandBoxTableRowName ); domZandBoxTableRow.append( domZandBoxTableRowId ); domZandBoxTableRow.append( domZandBoxTableRowAdd ); log( 4, 'log', 'Function.prototype.createNewMunzeeRow() returning new row DOM:\n\t%o', domZandBoxTableRow ); return domZandBoxTableRow; } Function.prototype.addTableRow = function ( arrSandPin, intIndex ) { log( 4, 'log', 'Function.prototype.addTableRow() creating row #%i for table with pin:\n\t%o', ( intIndex + 1 ), arrSandPin ); var domZandBoxTableRow = document.createElement( 'tr' ); var domZandBoxTableRowPin = document.createElement( 'td' ); var domZandBoxTableRowLat = document.createElement( 'td' ); var domZandBoxTableRowLon = document.createElement( 'td' ); var domZandBoxTableRowOwn = document.createElement( 'td' ); var domZandBoxTableRowName = document.createElement( 'td' ); var domZandBoxTableRowId = document.createElement( 'td' ); var domZandBoxTableRowSaveRemove = document.createElement( 'td' ); domZandBoxTableRow.id = 'ZandboxRow-' + ( intIndex + 1 ); domZandBoxTableRowId.style = 'display: none;'; domZandBoxTableRowId.className = 'hidden-id'; var domZandBoxTextPin = document.createTextNode( intIndex + 1 ); var domZandBoxInputLat = document.createElement( 'input' ); var domZandBoxInputLon = document.createElement( 'input' ); var domZandBoxInputOwn = document.createElement( 'input' ); var domZandBoxInputName = document.createElement( 'input' ); var domZandBoxInputId = document.createElement( 'input' ); var domZandBoxInputSave = document.createElement( 'input' ); var domZandBoxInputRemove = document.createElement( 'input' ); domZandBoxInputLat.type = 'text'; domZandBoxInputLon.type = 'text'; domZandBoxInputOwn.type = 'checkbox'; domZandBoxInputName.type = 'text'; domZandBoxInputId.type = 'number'; domZandBoxInputSave.type = 'button'; domZandBoxInputRemove.type = 'button'; domZandBoxInputLat.id = 'ZandboxRow-' + ( intIndex + 1 ) + '-lat'; domZandBoxInputLon.id = 'ZandboxRow-' + ( intIndex + 1 ) + '-lng'; domZandBoxInputOwn.id = 'ZandboxRow-' + ( intIndex + 1 ) + '-own'; domZandBoxInputName.id = 'ZandboxRow-' + ( intIndex + 1 ) + '-name'; domZandBoxInputId.id = 'ZandboxRow-' + ( intIndex + 1 ) + '-id'; domZandBoxInputLat.size = '25'; domZandBoxInputLon.size = '25'; domZandBoxInputName.maxlength = '33'; domZandBoxInputName.size = '35'; domZandBoxInputLat.style = 'text-align: right;'; domZandBoxInputLon.style = 'text-align: right;'; domZandBoxInputName.style = 'text-align: right;'; domZandBoxInputId.style = 'text-align: center;'; domZandBoxInputLat.setAttribute( 'value', ( arrSandPin[ 0 ] || 0 ) ); domZandBoxInputLon.setAttribute( 'value', ( arrSandPin[ 1 ] || 0 ) ); domZandBoxInputOwn.checked = ( arrSandPin[ 2 ] === 1 ? true : false ); domZandBoxInputName.setAttribute( 'value', ( arrSandPin[ 3 ] || '' ) ); domZandBoxInputId.setAttribute( 'value', ( arrSandPin[ 4 ] || '' ) ); domZandBoxInputSave.setAttribute( 'value', 'Save' ); domZandBoxInputSave.setAttribute( 'onClick', "Function.updateMunzee( parseInt( $( this ).parents( 'tr' ).attr( 'id' ).replace( 'ZandboxRow-', '' ) ) );" ); domZandBoxInputRemove.setAttribute( 'value', 'Remove' ); domZandBoxInputRemove.setAttribute( 'onClick', "Function.removeMunzee( parseInt( $( this ).parents( 'tr' ).attr( 'id' ).replace( 'ZandboxRow-', '' ) ) );" ); domZandBoxTableRowPin.append( domZandBoxTextPin ); domZandBoxTableRowLat.append( domZandBoxInputLat ); domZandBoxTableRowLon.append( domZandBoxInputLon ); domZandBoxTableRowOwn.append( domZandBoxInputOwn ); domZandBoxTableRowName.append( domZandBoxInputName ); domZandBoxTableRowId.append( domZandBoxInputId ); domZandBoxTableRowSaveRemove.append( domZandBoxInputSave ); domZandBoxTableRowSaveRemove.append( domZandBoxInputRemove ); domZandBoxTableRow.append( domZandBoxTableRowPin ); domZandBoxTableRow.append( domZandBoxTableRowLat ); domZandBoxTableRow.append( domZandBoxTableRowLon ); domZandBoxTableRow.append( domZandBoxTableRowOwn ); domZandBoxTableRow.append( domZandBoxTableRowName ); domZandBoxTableRow.append( domZandBoxTableRowId ); domZandBoxTableRow.append( domZandBoxTableRowSaveRemove ); log( 4, 'log', 'Function.prototype.addTableRow() returning new row DOM:\n\t%o', domZandBoxTableRow ); return domZandBoxTableRow; } Function.prototype.updateMunzee = function( valId ) { var intIndex = ( isNaN( valId ) ? parseInt( valId.replace( 'ZandboxRow-', '' ) ) : valId ); log( 4, 'log', 'Function.prototype.updateMunzee updating munzee (%o) %i (%s).', valId, ( intIndex - 1 ), munzeesandbox[ intIndex - 1 ][ 3 ] ); var objUpdatedMunzee = { lng: ( $( 'input#ZandboxRow-' + intIndex + '-lng' ).val() || map.getCenter().lng ), lat: ( $( 'input#ZandboxRow-' + intIndex + '-lat' ).val() || map.getCenter().lat ), name: ( $( 'input#ZandboxRow-' + intIndex + '-name' ).val() || 'Quick Deploy by " + username + "' ), id: ( $( 'input#ZandboxRow-' + intIndex + '-id' ).val() || ( intIndex - 1 ).toString() ), own: ( document.getElementById( 'ZandboxRow-' + intIndex + '-own' ).checked ? 1 : 0 ) }; // Update mapSandbox? log( 4, 'log', 'Function.prototype.updateMunzee() performing:\n\tmunzeesandbox[ %i ] = %o', ( intIndex - 1 ), [ objUpdatedMunzee.lng, objUpdatedMunzee.lat, objUpdatedMunzee.own, objUpdatedMunzee.name, objUpdatedMunzee.id ] ); munzeesandbox[ intIndex - 1 ] = [ objUpdatedMunzee.lat, objUpdatedMunzee.lng, objUpdatedMunzee.own, objUpdatedMunzee.name, objUpdatedMunzee.id ]; log( 4, 'log', 'Function.prototype.updateMunzee() performing:\n\tFunction.saveSandbox()' ); Function.saveSandbox(); } Function.prototype.removeMunzee = function ( valId ) { var intIndex = ( isNaN( valId ) ? parseInt( valId.replace( 'ZandboxRow-', '' ) ) : valId ); log( 4, 'log', 'Function.prototype.removeMunzee() removing munzee (%o) %i (%s) from sandbox.', valId, ( intIndex - 1 ), munzeesandbox[ intIndex - 1 ][ 3 ] ); log( 4, 'log', 'Function.prototype.removeMunzee() splicing %i (%s) from munzeesandbox', ( intIndex - 1 ), munzeesandbox[ intIndex - 1 ][ 3 ] ); munzeesandbox.splice( ( intIndex - 1 ), 1 );log( 4, 'info', 'Spliced %i from munzeesandbox leaving:\n\t%o', ( intIndex - 1 ), munzeesandbox ); log( 4, 'log', 'Function.prototype.removeMunzee() performing:\n\tFunction.saveSandbox()' ); Function.saveSandbox(); log( 4, 'log', 'Function.prototype.removeMunzee() performing:\n\tFunction.removeTableRow( \'%s\' )', intIndex ); Function.removeTableRow( intIndex ); } Function.prototype.addMunzee = function() { var objNewMunzee = { lng: ( $( 'input#NewMunzeeLng' ).val() || map.getCenter().lng ), lat: ( $( 'input#NewMunzeeLat' ).val() || map.getCenter().lat ), name: ( $( 'input#NewMunzeeName' ).val() || 'Quick Deploy by ' + username ), own: ( document.getElementById( 'NewMunzeeOwn' ).checked ? 1 : 0 ) }; log( 4, 'log', 'Function.prototype.addMunzee() performing:\n\tmapSandbox.addItem( %o, %o, %o )', [ objNewMunzee.lng, objNewMunzee.lat ], objNewMunzee.name, objNewMunzee.own ); mapSandbox.addItem( [ objNewMunzee.lng, objNewMunzee.lat ], objNewMunzee.name, objNewMunzee.own ); initilSB = 1; log( 4, 'log', 'Function.prototype.addMunzee() performing:\n\tmunzeesandbox.push( %o )', [ objNewMunzee.lat, objNewMunzee.lng, objNewMunzee.own, objNewMunzee.name, munzeesandboxcounter.toString() ] ); munzeesandbox.push( [ objNewMunzee.lat, objNewMunzee.lng, objNewMunzee.own, objNewMunzee.name, munzeesandboxcounter.toString() ] ); munzeesandboxcounter++; log( 4, 'info', 'munzeesandbox now contains:\n%o', munzeesandbox ); log( 4, 'log', 'Function.prototype.addMunzee() performing:\n\tFunction.removeTableRow( \'%s\' )', 'ZandboxNewRow' ); Function.removeTableRow( 'ZandboxNewRow' ); log( 4, 'log', 'Function.prototype.addMunzee() performing:\n\tFunction.addTableRow( %o, %i )', munzeesandbox[ munzeesandboxcounter - 1 ], munzeesandboxcounter - 1 ); $( 'table#ZandboxTable > tbody' ).append( Function.addTableRow( munzeesandbox[ munzeesandboxcounter - 1 ], munzeesandboxcounter - 1 ) ); log( 4, 'log', 'Function.prototype.addMunzee() performing:\n\tFunction.createNewMunzeeRow()' ); $( 'table#ZandboxTable > tbody' ).append( Function.createNewMunzeeRow() ); if ( isDebug ) { $( '.hidden-id' ).show(); } log( 4, 'log', 'Function.prototype.addMunzee() performing:\n\tFunction.saveSandbox()' ); Function.saveSandbox(); } var domClearButton = document.createElement( 'input' ); domClearButton.type = 'button'; domClearButton.id = 'clearSB'; domClearButton.classList.add( 'btn', 'btn-success', 'btn-medium-green', 'btn-xs', 'hidden-xs' ); domClearButton.style = 'margin-top: 10px; margin-right: 5px; width: 115px;'; domClearButton.setAttribute( 'onClick', "if(confirm('Click OK if you are sure you want to clear your sandbox:',false)){localStorage.removeItem( 'munzeesandboxcounter' );localStorage.removeItem( 'munzeesandbox' );}" ); domClearButton.value = 'clear sandbox'; var domZandboxDiv = document.createElement( 'div' ); domZandboxDiv.id = 'zandbox'; domZandboxDiv.className = 'panel-footer'; domZandboxDiv.style = 'text-align: center;'; var domZandboxTable = document.createElement( 'table' ); domZandboxTable.id = 'ZandboxTable'; domZandboxTable.style = 'width: 100%;'; domZandboxTable.append( createTableHead() ); var domZandboxTableBody = document.createElement( 'tbody' ); munzeesandbox.forEach( function( arrSandPin, intIndex, arrSandbox ) { domZandboxTableBody.append( Function.addTableRow( arrSandPin, intIndex ) ); } ); domZandboxTableBody.append( Function.createNewMunzeeRow() ); domZandboxTable.append( domZandboxTableBody ); domZandboxDiv.append( domZandboxTable ); ( function() { 'use strict'; log( 0, 'info', 'Script loaded.' ); $( 'div#sandbox' ).remove();// We're not going to use the default sandbox buttons anymore. $( 'input#showSBbuttons' ).click( function( event ) { event.preventDefault(); $( 'div#showsandbox' ).empty();// hide button mapSandbox = initSandbox();// initialize sandbox mapSandbox.length = localStorage.getItem( 'munzeesandboxcounter' ); var arrSandBoxMunzee = JSON.parse( localStorage.getItem( 'munzeesandbox' ) ); for ( var n in arrSandBoxMunzee ) { mapSandbox.addItem( [ arrSandBoxMunzee[ n ][ 1 ], arrSandBoxMunzee[ n ][ 0 ] ], arrSandBoxMunzee[ n ][ 3 ], arrSandBoxMunzee[ n ][ 2 ] ); } $( 'div.panel.panel-default' ).append( domZandboxDiv );// Add table with contents of sandbox if ( isDebug ) { $( '.hidden-id' ).show(); } } ); } )();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址