From fb2efe42f63149493d2bbe36fd67e3fc115db64e Mon Sep 17 00:00:00 2001 From: PureCS Date: Tue, 3 Jul 2018 08:17:52 -0700 Subject: [PATCH] Add client functions section --- src/Censorship.md | 24 +++ src/Class-Check.md | 146 +++++++------- src/Client-functions.md | 7 + src/Home.md | 17 +- src/Map-Region-System.md | 266 +++++++++++--------------- src/Mouse-coordinate-tracking.md | 16 ++ src/SUMMARY.md | 8 +- src/img/map-region-system-diagram.png | Bin 0 -> 12439 bytes src/img/map-region-system-loading.png | Bin 0 -> 22894 bytes 9 files changed, 242 insertions(+), 242 deletions(-) create mode 100644 src/Censorship.md create mode 100644 src/Client-functions.md create mode 100644 src/Mouse-coordinate-tracking.md create mode 100755 src/img/map-region-system-diagram.png create mode 100755 src/img/map-region-system-loading.png diff --git a/src/Censorship.md b/src/Censorship.md new file mode 100644 index 0000000..0a52e53 --- /dev/null +++ b/src/Censorship.md @@ -0,0 +1,24 @@ +# Censorship + +Chat message censorship is applied client-side. + +Traditionally, the use of bad words does not always result in a punishment, +unless if applied manually by a staff member. + +## Process + +There are four related cache files which are loaded and used in censorship. + +They are as follows: + +| Cache file name | Purpose | +|---|---| +| `fragmentsenc.txt` | ? | +| `badenc.txt` | Contains bad words, including variations (e.g. `fuck`, `fok`, etc.). | +| `domainenc.txt` | Contains bad domain names. | +| `tldlist.txt` | Contains possible top-level domain names. | + +When an input is received, if bad phrases are found they are replaced +with a sequence of astericks. + +Bad phrases are either a bad word, or a combination of a bad domain name and a top-level domain name. diff --git a/src/Class-Check.md b/src/Class-Check.md index 13b3a30..9e452cc 100644 --- a/src/Class-Check.md +++ b/src/Class-Check.md @@ -1,85 +1,89 @@ +# Class check + The class check originated with the new Runescape engine update which -took place around the 4xx revisions. It gives the Jagex servers the -ability to check the modifiers, update, or fetch the value for a field. +took place around the 4xx revisions. +It gives the Jagex servers the ability to check the modifiers, update, +or fetch the value for a field. It also gives functionality to invoke a method with parameters and get -it's return value, or check it's modifiers. Each of these -functionalities are described with a request type. A class check request -is built up with many of these request types. Each request is tagged -with an unique id. +it's return value, or check it's modifiers. +Each of these functionalities are described with a request type. +A class check request is built up with many of these request types. +Each request is tagged with an unique id. -== Request Structure == +## Request format -+-------------------------+ \| amount requests : ubyte \| -+-------------------------+ \| uid : dword \| -+-------------------------+--------------+------------------------+ \| -for each request \| type : ubyte \| type dependent data... \| -+-------------------------+--------------+------------------------+ +``` +unsigned byte numberOfRequests; +int uid; +byte[] requests_block; +``` -== Response Structure == +The `requests_block` is comprised of multiple requests, each with the following format: -+---------------------+ \| uid : dword \| -+---------------------+----------------------+------------------------+ -\| for each request \| response code : byte \| type dependent data... \| -+---------------------+----------------------+------------------------+ -\| payload crc : dword \| +---------------------+ +``` +unsigned byte type; +type-dependent data; +``` -== Request Types == +## Response format + +``` +int uid; +byte[] responses_block; +short payloadCrc; +``` + +The `responses_block` is comprised of multiple responses, each with the following format: + +``` +byte responseCode; +type-dependent data; +``` + +## Request Types For request types 0, 2, 4 there will only be one successful response -code and a dword value of the value being requested will be sent. For -request type 1, only the successful response code will be used but no +code and a short value of the value being requested will be sent. +For request type 1, only the successful response code will be used but no value will be sent back. -{\| border=2px ! Opcode ! Name ! Description \|- ! 0 ! Fetch Numeric -Field ! Fetches the value of a numeric field. \|- ! 1 ! Update Numeric -Field ! Updates the value of a numeric field. \|- ! 2 ! Get Field -Modifiers ! Gets the modifiers of a field. \|- ! 3 ! Invoke Method ! -Invokes a method and sends back its return object. \|- ! 4 ! Get Method -Modifiers ! Gets the modifiers of a method. \|} +| Opcode | Name | Description | +|---|---|---| +| 0 | Fetch fumeric field | Fetches the value of a numeric field. | +| 1 | Update numeric field | Updates the value of a numeric field. | +| 2 | Get field modifiers | Gets the modifiers of a field. | +| 3 | Invoke method | Invokes a method and sends back its return object. | +| 4 | Get method modifiers | Gets the modifiers of a method. | -== Return Codes == +## Return Codes -All the return codes are in descending priority by numerical order. For -opcode 0, there are cases where a numeric value is sent to the server on -fetch requests. This value is always a dword. For a method invoke -request, there isn't a value that is sent to the server. It is just -assumed that there wasn't a return object from the invoked method. +For opcode 0, there are cases where a numeric value is sent to the server +on fetch requests. +This value is always a short. -{\| border=2px ! Opcode ! Name ! On Receive/Response ! Description \|- ! -0 ! Successful ! Response ! Successfully executed the request. \|- ! 1 ! -Successful - Returned numeric value ! Response ! Successfully executed -the request, and returned a numeric value. \|- ! 2 ! Successful - -Returned string value ! Response ! Successfully executed the request, -and returned a string value. \|- ! 4 ! Successful - Returned object -value ! Response ! Successfully executed the request, and returned an -object value. \|- ! -1 ! ClassNotFoundException ! Receive ! A -ClassNotFoundException was thrown while receiving a request from the -server. \|- ! -2 ! SecurityException ! Receive ! A SecurityException was -thrown while receiving a request from the server. \|- ! -3 ! -NullPointerException ! Receive ! A NullPointerException was thrown while -receiving a request from the server. \|- ! -4 ! Exception ! Receive ! An -Exception was thrown while receiving a request from the server. \|- ! -5 -! Throwable ! Receive ! An error or exception was thrown while receiving -a request from the server. \|- ! -10 ! ClassNotFoundException ! Response -! A ClassNotFoundException was thrown while responding to a request from -the server. \|- ! -11 ! InvalidClassException ! Response ! An -InvalidClassException was thrown while responding to a request from the -server. \|- ! -12 ! StreamCorruptedException ! Response ! A -StreamCorruptedException was thrown while responding to a request from -the server. \|- ! -13 ! OptionalDataException ! Response ! An -OptionDataException was thrown while responding to a request from the -server. \|- ! -14 ! IllegalAccessException ! Response ! An -IllegalAccessException was thrown while responding to a request from the -server. \|- ! -15 ! IllegalArgumentException ! Response ! An -IllegalArgumentException was thrown while responding to a request from -the server. \|- ! -16 ! InvocationTargetException ! Response ! An -InvocationTargetException was thrown while responding to a request from -the server. \|- ! -17 ! SecurityException ! Response ! A -SecurityException was thrown while responding to a request from the -server. ! \|- ! -18 ! IOException ! Response ! An IOException was thrown -while responding to a request from the server. \|- ! -19 ! -NullPointerException ! Response ! A NullPointerException was thrown -while responding to a request from the server. \|- ! -20 ! Exception ! -Response ! An Exception was thrown while responding to a request from -the server. \|- ! -21 ! Throwable ! Response ! An error or exception was -thrown while receiving a request from the server. \|} +For a method invoke request, there isn't a value that is sent to the server. +It is just assumed that there wasn't a return object from the invoked method. + +| Opcode | Name | On Receive/Response | Description | +|---|---|---|---| +| 0 | Successful | Response | Successfully executed the request. | +| 1 | Successful - Returned numeric value | Response | Successfully executed the request, and returned a numeric value. | +| 2 | Successful - Returned string value | Response | Successfully executed the request, and returned a string value. | +| 4 | Successful - Returned object value | Response | Successfully executed the request, and returned an object value. | +| -1 | ClassNotFoundException | Receive | A ClassNotFoundException was thrown while receiving a request from the server. | +| -2 | SecurityException | Receive | A SecurityException was thrown while receiving a request from the server. | +| -3 | NullPointerException | Receive | A NullPointerException was thrown while receiving a request from the server. | +| -4 | Exception | Receive | An Exception was thrown while receiving a request from the server. | +| -5 | Throwable | Receive | An error or exception was thrown while receiving a request from the server. | +| -10 | ClassNotFoundException | Response | A ClassNotFoundException was thrown while responding to a request from the server. | +| -11 | InvalidClassException | Response | An InvalidClassException was thrown while responding to a request from the server. | +| -12 | StreamCorruptedException | Response | A StreamCorruptedException was thrown while responding to a request from the server. | +| -13 | OptionDataException | Response | An OptionDataException was thrown while responding to a request from the server. | +| -14 | IllegalAccessException | Response | An IllegalAccessException was thrown while responding to a request from the server. | +| -15 | IllegalArgumentException | Response | An IllegalArgumentException was thrown while responding to a request from the server. | +| -16 | InvocationTargetException | Response | An InvocationTargetException was thrown while responding to a request from the server. | +| -17 | SecurityException | Response | A SecurityException was thrown while responding to a request from the server. | +| -18 | IOException | Response | An IOException was thrown while responding to a request from the server. | +| -19 | NullPointerException | Response | A NullPointerException was thrown while responding to a request from the server. | +| -20 | Exception | Response | An Exception was thrown while responding to a request from the server. | +| -21 | Throwable | Response | An error or exception was thrown while receiving a request from the server. | diff --git a/src/Client-functions.md b/src/Client-functions.md new file mode 100644 index 0000000..d0bc9d0 --- /dev/null +++ b/src/Client-functions.md @@ -0,0 +1,7 @@ +# Client functions + +This section will describe the following: +- [Map region system](./Map-Region-System.html) +- [Censorship](./Censorship.html) +- [Mouse coordinate tracking](./Mouse-coordinate-tracking.html) +- [Class-Check](./Class-Check.html) diff --git a/src/Home.md b/src/Home.md index 2259021..1376448 100644 --- a/src/Home.md +++ b/src/Home.md @@ -2,7 +2,7 @@ A source of documentation for the RSC/RS2/RS3 protocols and related systems. -### Navigation +## Navigation * [About](About.html) * [Rules](Rules.html) * [IRC](IRC.html) @@ -10,17 +10,12 @@ A source of documentation for the RSC/RS2/RS3 protocols and related systems. * [DMCA Policy](DMCA-Policy.html) * [Privacy Policy](Privacy-policy.html) -### Game Protocol -* [[RSC|Category RSC]] (2001 - 2004) -* [[RS2|Category RS2]] (2004 - 2013) -* [[RS3|Category RS3]] (2013 - present) +## Game Protocol +* RSC (2001 - 2004) +* RS2 (2004 - 2013) +* RS3 (2013 - present) -### Cache +## Cache * [JAGGRAB protocol](./JAGGRAB-Protocol.html) * [Ondemand protocol](./Ondemand-Protocol.html) * [Archive format](./Archive-Format.html) - - -### Miscellaneous -* [[Custom Data Types|Data Types]] -* [[Map Region System]] \ No newline at end of file diff --git a/src/Map-Region-System.md b/src/Map-Region-System.md index 2758f9d..e5bf0c0 100644 --- a/src/Map-Region-System.md +++ b/src/Map-Region-System.md @@ -1,120 +1,150 @@ -== Intro == Everyone knows that a coordinate system is in place to -navigate through the Runescape world. That coordinate system is based -off upon three variables, the Absolute X, Y Z coordinates. Before we -continue to talk about how these three variables are used in -calculations lets set down some vocabulary: +# Map region system -== Definitions == ===Tile=== A tile is a representation of an absolute -coordinate. +A coordinate system is used to navigate through the RuneScape +world. +That coordinate system is based upon three variables, the absolute +X-, Y-, and Z-coordinates. -''Example: Varrock Coordinates 3211, 3424 represents one tile.'' +## Definitions -===Tile Chunk=== A chunk of tiles, 8 x 8 in size. Also known as a region -before the scope of a region was understood. The chunk is considered a -point so it has X and Y coordinates. There are two forms of a Chunk, -formatted and non; a formatted chunks equation is: +A **tile** is the in-game representation of an absolute coordinate. -int chunkX = (getAbsoluteX() \>\> 3) - 6; int chunkY = (getAbsoluteY() -\>\> 3) - 6; +e.g. The coordinates `(3222, 3222)` represents one tile in the heart +of the Lumbridge castle. + +A **chunk of tiles**, 8 x 8 in size. +Also known as a region before the scope of a region was understood. +The chunk is considered a point so it has X and Y coordinates. +There are two forms of a Chunk: formatted and non-formatted, +a formatted chunks equation is: + +```java +int chunkX = (getAbsoluteX() >> 3) - 6; +int chunkY = (getAbsoluteY() >> 3) - 6; +``` This centers the chunk on the map, more on that later. The normal chunk equation is: -int chunkX = (getAbsoluteX() \>\> 3); int chunkY = (getAbsoluteY() \>\> -3); +```java +int chunkX = (getAbsoluteX() >> 3); +int chunkY = (getAbsoluteY() >> 3); +``` -''Example: The Coordinates \[3211, 3424\] Chunk X (formatted) is 395 and -the Chunk Y (un-formatted) is 428.'' +e.g. For the coordinates `(3211, 3424)`, chunk X (formatted) is 395 and +the chunk Y (un-formatted) is 428.'' -===Region=== A region is 64 x 64 in size, or 8 x 8 in chunks. The region -is considered a point so it has X and Y coordinates. The equation for -finding the region the coordinates is within is: +## Region -int regionx = (getUnformattedRegionX() \>\> 3); -//getUnformatedRegionX()/8; int regiony = (getUnformattedRegionY() \>\> -3); //getUnformatedRegionY()/8; +A **region** is 64 x 64 in size, or 8 x 8 in chunks. +The region is considered a point so it has X and Y coordinates. -''Example: The Coordinates \[3211, 3424\] Region X is 50 and the Region -Y is 53.'' +The equation for finding the region the coordinates is within is: + +```java +int regionX = (getUnformattedRegionX() >> 3); // getUnformatedRegionX() / 8; +int regionY = (getUnformattedRegionY() >> 3); // getUnformatedRegionY() / 8; +``` + +e.g. For the coordinates `(3211, 3424)`, region X is 50, and the +region Y is 53. Note: The Region X and Region Y coordinates are traditionally not used in server location calculations; but practical region systems should use this calculation for many purposes. -===Map=== There is no calculation for a map, and there is no Map X or -Map Y. A Map is, however, a 104 x 104 area made up of 13 x 13 chunks. -Why is the number not even you may ask? Because it has a center. The -\[7, 7\] map chunk of the map is the center, and is also the formatted -chunk. When a region update is called by the server, a new map is -called, but you must understand that the formatted chunk never changes; -the tiles in the map, however, are updated and trimmed. When the player -moves out of the formatted chunk, the map is re-positioned to make that -chunk the center yet again. As I said, a new update is not needed every -time the player enters a new region, but when the range of +- 32 from -the point in the center of the chunk is reached, an update is required -to update the map to the new objects so that the 'black space' or fog is -not reached. Confused? +## Map -===Diagram=== \[http://i.imgur.com/C3huO.png External Image\] +There is no calculation for a map, and there is no Map X or Map Y. -The active chunk is the chunk in which the player resides. The definite -rendering chunks are the chunks in which will be rendered on the players -screen no matter where they are in the active chunk. The indefinite -rendering chunks are the chunks in which depending on where the player -is within the active chunk they may be rendered or not. Remember this -depends on the +- distance of 32 from the players absolute position. The -queue chunks are pre-loaded chunks in which after the active chunk is -moved may be disposed of or activated depending upon the direction in -which the active chunk changes. +A Map is, however, a 104 x 104 area made up of 13 x 13 chunks. +Why is the number not even you may ask? +Because it has a center. +The `(7, 7)` map chunk of the map is the center, and is also the formatted +chunk. -==Loading== +When a region update is called by the server, a new map is called, but you +must understand that the formatted chunk never changes; the tiles in the +map, however, are updated and trimmed. +When the player moves out of the formatted chunk, the map is re-positioned +to make that chunk the center yet again. +As stated, a new update is not needed every time the player enters a +new region, but when the range of +- 32 from the point in the center of +the chunk is reached, an update is required to update the map to the +new objects so that the 'black space' or fog is not reached. Confused? -These were the regions loaded for the coordinates \[3183, 3217\]: +## Diagram -\[http://i.imgur.com/ydl78.png External Image\] +![Diagram](./img/map-region-system-diagram.png) + +The active chunk is the chunk in which the player resides. +The definite rendering chunks are the chunks in which will be rendered +on the players screen no matter where they are in the active chunk. +The indefinite rendering chunks are the chunks in which depending on +where the player is within the active chunk they may be rendered or not. +Remember this depends on the +- distance of 32 from the players +absolute position. The queue chunks are pre-loaded chunks in whichafter the +active chunk is moved may be disposed of or activated depending upon the +direction in which the active chunk changes. + +## Loading + +The following were the regions loaded for the coordinates `(3183, 3217)`: + +![Loading diagram](./img/map-region-system-loading.png) If you can imagine a puzzle, a 64 x 64 piece does not fit equally within -the 104 x 104 area. So bits of each region are taken that are within the -104 x 104 map area. +the 104 x 104 area. +So, bits of each region are taken that are within the 104 x 104 map area. The amount of regions that are to be loaded can be calculated this way: Please note that Region X and Region Y are not formatted. -int amt = 0; for(int i21 = (player.getLocation().getRegionX() - 6) / 8; -i21 \<= (player.getLocation().getRegionX() + 6) / 8; i21++) { for(int -k23 = (player.getLocation().getRegionY() - 6) / 8; k23 \<= -(player.getLocation().getRegionY() + 6) / 8; k23++) amt++; } +```java +int amt = 0; + +for (int i21 = (player.getLocation().getRegionX() - 6) / 8; i21 <= (player.getLocation().getRegionX() + 6) / 8; i21++) { + for (int k23 = (player.getLocation().getRegionY() - 6) / 8; k23 <= (player.getLocation().getRegionY() + 6) / 8; k23++) + amt++; +} +``` Along with this, the base X and base Y of each of the region can be calculated: -for(int i21 = (player.getLocation().getRegionX() - 6) / 8; i21 \<= -(player.getLocation().getRegionX() + 6) / 8; i21++) { for(int k23 = -(player.getLocation().getRegionY() - 6) / 8; k23 \<= -(player.getLocation().getRegionY() + 6) / 8; k23++) -System.out.println(i21+\" X "+(i21 \<\< 6)+","+k23+" Y \"+(k23 \<\< -6));;; } +```java +for (int i21 = (player.getLocation().getRegionX() - 6) / 8; i21 <= (player.getLocation().getRegionX() + 6) / 8; i21++) { + for (int k23 = (player.getLocation().getRegionY() - 6) / 8; k23 <= (player.getLocation().getRegionY() + 6) / 8; k23++) + System.out.println(i21 + " X " + (i21 << 6) + "," + k23 + " Y " + (k23 << 6));;; +} + ``` The 'X' and 'Y' coordinates represents the coordinates of the region as depicted in the diagram. After the regions are loaded they are trimmed to the tiles that are necessary. -Well hope this gave you some idea of how regions are loaded and such, -tell me if you need explanation on anything. +## Example Location class -Heres an example of a location class that I wrote, sorry for the lack of -comments. If you read everything then this should make sense: +The following is an example Location class written by sinisoul. +It is not heavily commented due to it being a very simple class, +and it should be easy to follow if you read this section in full. -package net.forge.content.world.node; /\*\* \* RuneForge \| 317 \* -Location.java \* @version 1.0.0 \* @author SiniSoul (SiniSoul\@live.com) -\*/ public final class Location { +```java +package net.forge.content.world.node; + +/** + * RuneForge (317) + * @version 1.0.0 + * @author SiniSoul (SiniSoul@live.com) + */ +public final class Location { /** * The Tile X and Y coordinates. */ - private int tilex = 0, + private int tilex = 0, tiley = 0; /** @@ -128,174 +158,96 @@ Location.java \* @version 1.0.0 \* @author SiniSoul (SiniSoul\@live.com) private int chunkx = 0, chunky = 0; - /** - * - * @param tilex - */ public void setTileX(int tilex) { this.tilex = (tilex & 0xFFFF); } - /** - * - * @return - */ public int getTileX() { return tilex; } - /** - * - * @param tilex - */ public void setTileY(int tiley) { this.tiley = (tiley & 0xFFFF); } - /** - * - * @return - */ public int getTileY() { return tiley; } /** - * - * @param formated If the chunk is formatted for map positioning or + * @param formatted If the chunk is formatted for map positioning or * other formatted chunk comparison. - * @return */ - public int calculateChunkX(boolean formated) { - return formated ? (getTileX() >> 3) - 6 : (getTileX() >> 3); + public int calculateChunkX(boolean formatted) { + return formatted ? (getTileX() >> 3) - 6 : (getTileX() >> 3); } /** - * - * @param formated If the chunk is formatted for map positioning or + * @param formatted If the chunk is formatted for map positioning or * other formatted chunk comparison. - * @return */ - public int calculateChunkY(boolean formated) { - return formated ? (getTileY() >> 3) - 6 : (getTileY() >> 3); + public int calculateChunkY(boolean formatted) { + return formatted ? (getTileY() >> 3) - 6 : (getTileY() >> 3); } - /** - * - */ public void updateChunkX() { this.chunkx = calculateChunkX(true); } - /** - * - */ public void updateChunkY() { this.chunkx = calculateChunkY(true); } - /** - * - * @return - */ public int getChunkX() { return chunkx; } - /** - * - * @return - */ public int getMapLocalX() { return getTileX() - (getChunkX() << 3); } - /** - * - * @return - */ public int getChunkY() { return chunky; } - /** - * - * @return - */ public int getMapLocalY() { return getTileX() - (getChunkY() << 3); } - /** - * - * @param height - */ public void setHeight(int height) { this.height = (height & 0x3); } - /** - * - * @return - */ public int getHeight() { return height; } - /** - * - * @return - */ public int getRegionX() { return calculateChunkX(false) >> 3; } - /** - * - * @return - */ public int getRegionLocalX() { return getTileX() - (getRegionX() << 6); } - /** - * - * @return - */ public int getRegionY() { return calculateChunkY(false) >> 3; } - /** - * - * @return - */ public int getRegionLocalY() { return getTileY() - (getRegionY() << 6); } - /** - * - * @param tilex - * @param tiley - * @param height - */ public void set(int tilex, int tiley, int height) { setTileX(tilex); setTileY(tiley); setHeight(height); } - /** - * - * @param tilex - * @param tiley - * @param height - */ public Location(int tilex, int tiley, int height) { set(tilex, tiley, height); updateChunkX(); updateChunkY(); } - } +``` diff --git a/src/Mouse-coordinate-tracking.md b/src/Mouse-coordinate-tracking.md new file mode 100644 index 0000000..d7abb18 --- /dev/null +++ b/src/Mouse-coordinate-tracking.md @@ -0,0 +1,16 @@ +# Mouse coordinate tracking + +There is a mechanicsm of mouse coordinate tracking within the client. +This records the `(x, y)` coordinates of the mouse, and sends them +back to the server each tick. + +When the client connects with the server, after it receives +the player privilege, it receives a byte denoting whether or not +the client should send these coordinates to the server periodically. + +## Packet structure +``` +byte opcode = 45; +byte dummy = 0; +byte[] mouse_data; +``` diff --git a/src/SUMMARY.md b/src/SUMMARY.md index b74cc3d..e4783e4 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -18,9 +18,11 @@ - [Ondemand protocol](./Ondemand-Protocol.md) - [Archive format](./Archive-Format.md) - [OB3](./OB3.md) -- [Class-Check](./Class-Check.md) -- [Map-Region-System](./Map-Region-System.md) -- [RS-String](./RS-String.md) +- [Client functions](./Client-functions.md) + - [Map region system](./Map-Region-System.md) + - [Censorship](./Censorship.md) + - [Mouse coordinate tracking](./Mouse-coordinate-tracking.md) + - [Class-Check](./Class-Check.md) - [Template-Packet](./Template-Packet.md) - [135-Protocol](./135-Protocol.md) - [194-Clear-screen](./194-Clear-screen.md) diff --git a/src/img/map-region-system-diagram.png b/src/img/map-region-system-diagram.png new file mode 100755 index 0000000000000000000000000000000000000000..422f456b65b91df0f5aa3146eb393f46f971c9b1 GIT binary patch literal 12439 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