支持spine4.3
This commit is contained in:
1 parent
63e4f61631
commit
0656684a92
206 files changed
+100597
-1320
No files matched your search
+483
@@ -0,0 +1,483 @@
|
||||
/******************************************************************************
|
||||
* Spine Runtimes License Agreement
|
||||
* Last updated April 5, 2025. Replaces all prior versions.
|
||||
*
|
||||
* Copyright (c) 2013-2025, Esoteric Software LLC
|
||||
*
|
||||
* Integration of the Spine Runtimes into software or otherwise creating
|
||||
* derivative works of the Spine Runtimes is permitted under the terms and
|
||||
* conditions of Section 2 of the Spine Editor License Agreement:
|
||||
* http://esotericsoftware.com/spine-editor-license
|
||||
*
|
||||
* Otherwise, it is permitted to integrate the Spine Runtimes into software
|
||||
* or otherwise create derivative works of the Spine Runtimes (collectively,
|
||||
* "Products"), provided that each user of the Products must obtain their own
|
||||
* Spine Editor license and redistribution of the Products in any form must
|
||||
* include this license and copyright notice.
|
||||
*
|
||||
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
|
||||
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
import { ClippingAttachment } from "./attachments/ClippingAttachment.js";
|
||||
import { MeshAttachment } from "./attachments/MeshAttachment.js";
|
||||
import { RegionAttachment } from "./attachments/RegionAttachment.js";
|
||||
import { Bone } from "./Bone.js";
|
||||
import { DrawOrder } from "./DrawOrder.js";
|
||||
import { PhysicsConstraint } from "./PhysicsConstraint.js";
|
||||
import { Slot } from "./Slot.js";
|
||||
import { Color, Utils, Vector2 } from "./Utils.js";
|
||||
/** Stores bones and slots to be posed by animations and application code. Multiple skeleton instances can share the same
|
||||
* {@link SkeletonData}, including animations, attachments, and skins.
|
||||
*
|
||||
* After posing, call {@link updateWorldTransform} to apply constraints and compute world transforms for rendering.
|
||||
*
|
||||
* See [Instance objects](http://esotericsoftware.com/spine-runtime-architecture#Instance-objects) in the Spine Runtimes Guide. */
|
||||
export class Skeleton {
|
||||
static quadTriangles = [0, 1, 2, 2, 3, 0];
|
||||
static yDown = false;
|
||||
static get yDir() {
|
||||
return Skeleton.yDown ? -1 : 1;
|
||||
}
|
||||
/** The skeleton's setup pose data. */
|
||||
data;
|
||||
/** The skeleton's bones, sorted parent first. The root bone is always the first bone. */
|
||||
bones;
|
||||
/** The skeleton's slots. To add a slot, also add it to {@link DrawOrder.pose}. */
|
||||
slots;
|
||||
/** The skeleton's draw order. Use {@link DrawOrder.appliedPose} for rendering and {@link DrawOrder.pose} for changing the draw
|
||||
* order. */
|
||||
drawOrder;
|
||||
/** The skeleton's constraints. */
|
||||
// biome-ignore lint/suspicious/noExplicitAny: reference runtime does not restrict to specific types
|
||||
constraints;
|
||||
/** The skeleton's physics constraints. */
|
||||
physics;
|
||||
/** The list of bones and constraints, sorted in the order they should be updated, as computed by {@link updateCache}. */
|
||||
// biome-ignore lint/suspicious/noExplicitAny: reference runtime does not restrict to specific types
|
||||
_updateCache = [];
|
||||
// biome-ignore lint/suspicious/noExplicitAny: reference runtime does not restrict to specific types
|
||||
resetCache = [];
|
||||
/** The skeleton's current skin. May be null. */
|
||||
skin = null;
|
||||
/** The color to tint all the skeleton's attachments. */
|
||||
color;
|
||||
/** Scales the entire skeleton on the X axis.
|
||||
*
|
||||
* Bones that do not inherit scale are still affected by this property. */
|
||||
scaleX = 1;
|
||||
_scaleY = 1;
|
||||
/** Scales the entire skeleton on the Y axis.
|
||||
*
|
||||
* Bones that do not inherit scale are still affected by this property. */
|
||||
get scaleY() {
|
||||
return this._scaleY * Skeleton.yDir;
|
||||
}
|
||||
set scaleY(scaleY) {
|
||||
this._scaleY = scaleY;
|
||||
}
|
||||
/** Sets the skeleton X position, which is added to the root bone worldX position.
|
||||
*
|
||||
* Bones that do not inherit translation are still affected by this property. */
|
||||
x = 0;
|
||||
/** Sets the skeleton Y position, which is added to the root bone worldY position.
|
||||
*
|
||||
* Bones that do not inherit translation are still affected by this property. */
|
||||
y = 0;
|
||||
/** Returns the skeleton's time, is used for time-based manipulations, such as {@link PhysicsConstraint}.
|
||||
*
|
||||
* See {@link _update}. */
|
||||
time = 0;
|
||||
/** The x component of a vector that defines the direction {@link PhysicsConstraintPose.wind} is applied. */
|
||||
windX = 1;
|
||||
/** The y component of a vector that defines the direction {@link PhysicsConstraintPose.wind} is applied. */
|
||||
windY = 0;
|
||||
/** The x component of a vector that defines the direction {@link PhysicsConstraintPose.gravity} is applied. */
|
||||
gravityX = 0;
|
||||
/** The y component of a vector that defines the direction {@link PhysicsConstraintPose.gravity} is applied. */
|
||||
gravityY = 1;
|
||||
_update = 0;
|
||||
constructor(data) {
|
||||
if (!data)
|
||||
throw new Error("data cannot be null.");
|
||||
this.data = data;
|
||||
this.bones = [];
|
||||
for (let i = 0; i < data.bones.length; i++) {
|
||||
const boneData = data.bones[i];
|
||||
let bone;
|
||||
if (!boneData.parent)
|
||||
bone = new Bone(boneData, null);
|
||||
else {
|
||||
const parent = this.bones[boneData.parent.index];
|
||||
bone = new Bone(boneData, parent);
|
||||
parent.children.push(bone);
|
||||
}
|
||||
this.bones.push(bone);
|
||||
}
|
||||
this.slots = [];
|
||||
for (const slotData of this.data.slots)
|
||||
this.slots.push(new Slot(slotData, this));
|
||||
this.drawOrder = new DrawOrder(this.slots);
|
||||
this.physics = [];
|
||||
// biome-ignore lint/suspicious/noExplicitAny: reference runtime does not restrict to specific types
|
||||
this.constraints = [];
|
||||
for (const constraintData of this.data.constraints) {
|
||||
const constraint = constraintData.create(this);
|
||||
if (constraint instanceof PhysicsConstraint)
|
||||
this.physics.push(constraint);
|
||||
this.constraints.push(constraint);
|
||||
}
|
||||
this.color = new Color(1, 1, 1, 1);
|
||||
this.updateCache();
|
||||
}
|
||||
/** Caches information about bones and constraints. Must be called if the {@link skin} is modified or if bones, constraints,
|
||||
* or weighted path attachments are added or removed. */
|
||||
updateCache() {
|
||||
this._updateCache.length = 0;
|
||||
this.resetCache.length = 0;
|
||||
this.drawOrder.unconstrained();
|
||||
const slots = this.slots;
|
||||
for (let i = 0, n = slots.length; i < n; i++)
|
||||
slots[i].unconstrained();
|
||||
const bones = this.bones;
|
||||
const boneCount = bones.length;
|
||||
for (let i = 0, n = boneCount; i < n; i++) {
|
||||
const bone = bones[i];
|
||||
bone.sorted = bone.data.skinRequired;
|
||||
bone.active = !bone.sorted;
|
||||
bone.unconstrained();
|
||||
}
|
||||
if (this.skin) {
|
||||
const skinBones = this.skin.bones;
|
||||
for (let i = 0, n = this.skin.bones.length; i < n; i++) {
|
||||
let bone = this.bones[skinBones[i].index];
|
||||
do {
|
||||
bone.sorted = false;
|
||||
bone.active = true;
|
||||
bone = bone.parent;
|
||||
} while (bone);
|
||||
}
|
||||
}
|
||||
const constraints = this.constraints;
|
||||
let n = this.constraints.length;
|
||||
for (let i = 0; i < n; i++)
|
||||
constraints[i].unconstrained();
|
||||
for (let i = 0; i < n; i++) {
|
||||
const constraint = constraints[i];
|
||||
constraint.active = constraint.isSourceActive()
|
||||
// biome-ignore lint/complexity/useOptionalChain: changing to this might return undefined
|
||||
&& (!constraint.data.skinRequired || (this.skin != null && this.skin.constraints.includes(constraint.data)));
|
||||
if (constraint.active)
|
||||
constraint.sort(this);
|
||||
}
|
||||
for (let i = 0; i < boneCount; i++)
|
||||
this.sortBone(bones[i]);
|
||||
n = this._updateCache.length;
|
||||
for (let i = 0; i < n; i++) {
|
||||
const updateable = this._updateCache[i];
|
||||
if (updateable instanceof Bone)
|
||||
this._updateCache[i] = updateable.appliedPose;
|
||||
}
|
||||
}
|
||||
// biome-ignore lint/suspicious/noExplicitAny: reference runtime does not restrict to specific types
|
||||
constrained(object) {
|
||||
if (object.pose === object.appliedPose) {
|
||||
object.constrained();
|
||||
this.resetCache.push(object);
|
||||
}
|
||||
}
|
||||
sortBone(bone) {
|
||||
if (bone.sorted || !bone.active)
|
||||
return;
|
||||
const parent = bone.parent;
|
||||
if (parent)
|
||||
this.sortBone(parent);
|
||||
bone.sorted = true;
|
||||
this._updateCache.push(bone);
|
||||
}
|
||||
sortReset(bones) {
|
||||
for (let i = 0, n = bones.length; i < n; i++) {
|
||||
const bone = bones[i];
|
||||
if (bone.active) {
|
||||
if (bone.sorted)
|
||||
this.sortReset(bone.children);
|
||||
bone.sorted = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
/** Updates the world transform for each bone and applies all constraints.
|
||||
*
|
||||
* See <a href="https://esotericsoftware.com/spine-runtime-skeletons#World-transforms">World transforms</a> in the Spine
|
||||
* Runtimes Guide. */
|
||||
updateWorldTransform(physics) {
|
||||
this._update++;
|
||||
if (this.drawOrder.appliedPose === this.drawOrder.constrainedPose)
|
||||
this.drawOrder.resetConstrained();
|
||||
const resetCache = this.resetCache;
|
||||
for (let i = 0, n = this.resetCache.length; i < n; i++)
|
||||
resetCache[i].resetConstrained();
|
||||
const updateCache = this._updateCache;
|
||||
for (let i = 0, n = this._updateCache.length; i < n; i++)
|
||||
updateCache[i].update(this, physics);
|
||||
}
|
||||
/** Sets the bones, constraints, and slots to their setup pose values. */
|
||||
setupPose() {
|
||||
this.setupPoseBones();
|
||||
this.setupPoseSlots();
|
||||
}
|
||||
/** Sets the bones and constraints to their setup pose values. */
|
||||
setupPoseBones() {
|
||||
const bones = this.bones;
|
||||
for (let i = 0, n = bones.length; i < n; i++)
|
||||
bones[i].setupPose();
|
||||
const constraints = this.constraints;
|
||||
for (let i = 0, n = constraints.length; i < n; i++)
|
||||
constraints[i].setupPose();
|
||||
}
|
||||
/** Sets the slots and draw order to their setup pose values. */
|
||||
setupPoseSlots() {
|
||||
this.drawOrder.setupPose();
|
||||
const slots = this.slots;
|
||||
for (let i = 0, n = slots.length; i < n; i++)
|
||||
slots[i].setupPose();
|
||||
}
|
||||
/** Returns the root bone, or null if the skeleton has no bones. */
|
||||
getRootBone() {
|
||||
if (this.bones.length === 0)
|
||||
return null;
|
||||
return this.bones[0];
|
||||
}
|
||||
/** Finds a bone by comparing each bone's name. It is more efficient to cache the results of this method than to call it
|
||||
* repeatedly. */
|
||||
findBone(boneName) {
|
||||
if (!boneName)
|
||||
throw new Error("boneName cannot be null.");
|
||||
const bones = this.bones;
|
||||
for (let i = 0, n = bones.length; i < n; i++)
|
||||
if (bones[i].data.name === boneName)
|
||||
return bones[i];
|
||||
return null;
|
||||
}
|
||||
/** Finds a slot by comparing each slot's name. It is more efficient to cache the results of this method than to call it
|
||||
* repeatedly. */
|
||||
findSlot(slotName) {
|
||||
if (!slotName)
|
||||
throw new Error("slotName cannot be null.");
|
||||
const slots = this.slots;
|
||||
for (let i = 0, n = slots.length; i < n; i++)
|
||||
if (slots[i].data.name === slotName)
|
||||
return slots[i];
|
||||
return null;
|
||||
}
|
||||
setSkin(newSkin) {
|
||||
if (typeof newSkin === "string")
|
||||
this.setSkinByName(newSkin);
|
||||
else
|
||||
this.setSkinBySkin(newSkin);
|
||||
}
|
||||
;
|
||||
setSkinByName(skinName) {
|
||||
const skin = this.data.findSkin(skinName);
|
||||
if (!skin)
|
||||
throw new Error(`Skin not found: ${skinName}`);
|
||||
this.setSkin(skin);
|
||||
}
|
||||
setSkinBySkin(newSkin) {
|
||||
if (newSkin === this.skin)
|
||||
return;
|
||||
if (newSkin) {
|
||||
if (this.skin)
|
||||
newSkin.attachAll(this, this.skin);
|
||||
else {
|
||||
const slots = this.slots;
|
||||
for (let i = 0, n = slots.length; i < n; i++) {
|
||||
const slot = slots[i];
|
||||
const name = slot.data.attachmentName;
|
||||
if (name) {
|
||||
const attachment = newSkin.getAttachment(i, name);
|
||||
if (attachment)
|
||||
slot.pose.setAttachment(attachment);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.skin = newSkin;
|
||||
this.updateCache();
|
||||
}
|
||||
getAttachment(slotNameOrIndex, placeholder) {
|
||||
if (typeof slotNameOrIndex === 'string')
|
||||
return this.getAttachmentByName(slotNameOrIndex, placeholder);
|
||||
return this.getAttachmentByIndex(slotNameOrIndex, placeholder);
|
||||
}
|
||||
/** Finds an attachment by looking in the {@link skin} and {@link SkeletonData.defaultSkin} using the slot name and attachment
|
||||
* name.
|
||||
*
|
||||
* See {@link getAttachment}.
|
||||
* @returns May be null. */
|
||||
getAttachmentByName(slotName, placeholder) {
|
||||
const slot = this.data.findSlot(slotName);
|
||||
if (!slot)
|
||||
throw new Error(`Can't find slot with name ${slotName}`);
|
||||
return this.getAttachment(slot.index, placeholder);
|
||||
}
|
||||
/** Finds an attachment by looking in the {@link skin} and {@link SkeletonData.defaultSkin} using the slot index and
|
||||
* attachment name. First the skin is checked and if the attachment was not found, the default skin is checked.
|
||||
*
|
||||
* See [Runtime skins](http://esotericsoftware.com/spine-runtime-skins) in the Spine Runtimes Guide.
|
||||
* @returns May be null. */
|
||||
getAttachmentByIndex(slotIndex, placeholder) {
|
||||
if (!placeholder)
|
||||
throw new Error("placeholder cannot be null.");
|
||||
if (this.skin) {
|
||||
const attachment = this.skin.getAttachment(slotIndex, placeholder);
|
||||
if (attachment)
|
||||
return attachment;
|
||||
}
|
||||
if (this.data.defaultSkin)
|
||||
return this.data.defaultSkin.getAttachment(slotIndex, placeholder);
|
||||
return null;
|
||||
}
|
||||
/** A convenience method to set an attachment by finding the slot with {@link findSlot}, finding the attachment with
|
||||
* {@link getAttachment}, then setting the slot's {@link Slot.attachment}.
|
||||
* @param placeholder May be null to clear the slot's attachment. */
|
||||
setAttachment(slotName, placeholder) {
|
||||
if (!slotName)
|
||||
throw new Error("slotName cannot be null.");
|
||||
const slot = this.findSlot(slotName);
|
||||
if (!slot)
|
||||
throw new Error(`Slot not found: ${slotName}`);
|
||||
let attachment = null;
|
||||
if (placeholder) {
|
||||
attachment = this.getAttachment(slot.data.index, placeholder);
|
||||
if (!attachment)
|
||||
throw new Error(`Attachment not found: ${placeholder}, for slot: ${slotName}`);
|
||||
}
|
||||
slot.pose.setAttachment(attachment);
|
||||
}
|
||||
/** Finds a constraint of the specified type by comparing each constraints's name. It is more efficient to cache the results of
|
||||
* this method than to call it multiple times. */
|
||||
// biome-ignore lint/suspicious/noExplicitAny: reference runtime does not restrict to specific types
|
||||
findConstraint(constraintName, type) {
|
||||
if (constraintName == null)
|
||||
throw new Error("constraintName cannot be null.");
|
||||
if (type == null)
|
||||
throw new Error("type cannot be null.");
|
||||
const constraints = this.constraints;
|
||||
for (let i = 0, n = constraints.length; i < n; i++) {
|
||||
const constraint = constraints[i];
|
||||
if (constraint instanceof type && constraint.data.name === constraintName)
|
||||
return constraint;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/** Returns the axis aligned bounding box (AABB) of the region and mesh attachments for the applied pose.
|
||||
* @param offset An output value, the distance from the skeleton origin to the bottom left corner of the AABB.
|
||||
* @param size An output value, the width and height of the AABB.
|
||||
* @param temp Working memory to temporarily store attachments' computed world vertices. */
|
||||
getBoundsRect(clipper) {
|
||||
const offset = new Vector2();
|
||||
const size = new Vector2();
|
||||
this.getBounds(offset, size, undefined, clipper);
|
||||
return { x: offset.x, y: offset.y, width: size.x, height: size.y };
|
||||
}
|
||||
/** Returns the axis aligned bounding box (AABB) of the region and mesh attachments for the applied pose. Optionally applies
|
||||
* clipping.
|
||||
* @param offset An output value, the distance from the skeleton origin to the bottom left corner of the AABB.
|
||||
* @param size An output value, the width and height of the AABB.
|
||||
* @param temp Working memory to temporarily store attachments' computed world vertices.
|
||||
* @param clipper {@link SkeletonClipping} to use. If `null`, no clipping is applied. */
|
||||
getBounds(offset, size, temp = new Array(2), clipper = null) {
|
||||
if (!offset)
|
||||
throw new Error("offset cannot be null.");
|
||||
if (!size)
|
||||
throw new Error("size cannot be null.");
|
||||
const drawOrder = this.drawOrder.appliedPose;
|
||||
const slots = drawOrder;
|
||||
let minX = Number.POSITIVE_INFINITY, minY = Number.POSITIVE_INFINITY, maxX = Number.NEGATIVE_INFINITY, maxY = Number.NEGATIVE_INFINITY;
|
||||
for (let i = 0, n = drawOrder.length; i < n; i++) {
|
||||
const slot = slots[i];
|
||||
if (!slot.bone.active)
|
||||
continue;
|
||||
let verticesLength = 0;
|
||||
let vertices = null;
|
||||
let triangles = null;
|
||||
const attachment = slot.appliedPose.attachment;
|
||||
if (attachment) {
|
||||
if (attachment instanceof RegionAttachment) {
|
||||
verticesLength = 8;
|
||||
vertices = Utils.setArraySize(temp, verticesLength, 0);
|
||||
attachment.computeWorldVertices(slot, attachment.getOffsets(slot.appliedPose), vertices, 0, 2);
|
||||
triangles = Skeleton.quadTriangles;
|
||||
}
|
||||
else if (attachment instanceof MeshAttachment) {
|
||||
verticesLength = attachment.worldVerticesLength;
|
||||
vertices = Utils.setArraySize(temp, verticesLength, 0);
|
||||
attachment.computeWorldVertices(this, slot, 0, verticesLength, vertices, 0, 2);
|
||||
triangles = attachment.triangles;
|
||||
}
|
||||
else if (attachment instanceof ClippingAttachment && clipper) {
|
||||
clipper.clipEnd(slot);
|
||||
clipper.clipStart(this, slot, attachment);
|
||||
continue;
|
||||
}
|
||||
if (vertices && triangles) {
|
||||
if (clipper?.isClipping() && clipper.clipTriangles(vertices, triangles, triangles.length)) {
|
||||
vertices = clipper.clippedVertices;
|
||||
verticesLength = clipper.clippedVertices.length;
|
||||
}
|
||||
for (let ii = 0, nn = vertices.length; ii < nn; ii += 2) {
|
||||
const x = vertices[ii], y = vertices[ii + 1];
|
||||
minX = Math.min(minX, x);
|
||||
minY = Math.min(minY, y);
|
||||
maxX = Math.max(maxX, x);
|
||||
maxY = Math.max(maxY, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (clipper)
|
||||
clipper.clipEnd(slot);
|
||||
}
|
||||
if (clipper)
|
||||
clipper.clipEnd();
|
||||
offset.set(minX, minY);
|
||||
size.set(maxX - minX, maxY - minY);
|
||||
}
|
||||
/** Scales the entire skeleton on the X and Y axes.
|
||||
*
|
||||
* Bones that do not inherit scale are still affected by this property. */
|
||||
setScale(scaleX, scaleY) {
|
||||
this.scaleX = scaleX;
|
||||
this.scaleY = scaleY;
|
||||
}
|
||||
/** Sets the skeleton X and Y position, which is added to the root bone worldX and worldY position.
|
||||
*
|
||||
* Bones that do not inherit translation are still affected by this property. */
|
||||
setPosition(x, y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
/** Increments the skeleton's {@link time}. */
|
||||
update(delta) {
|
||||
this.time += delta;
|
||||
}
|
||||
/** Calls {@link PhysicsConstraint.translate} for each physics constraint. */
|
||||
physicsTranslate(x, y) {
|
||||
const constraints = this.physics;
|
||||
for (let i = 0, n = constraints.length; i < n; i++)
|
||||
constraints[i].translate(x, y);
|
||||
}
|
||||
/** Calls {@link PhysicsConstraint.rotate} for each physics constraint. */
|
||||
physicsRotate(x, y, degrees) {
|
||||
const constraints = this.physics;
|
||||
for (let i = 0, n = constraints.length; i < n; i++)
|
||||
constraints[i].rotate(x, y, degrees);
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2tlbGV0b24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvU2tlbGV0b24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OzsrRUEyQitFO0FBSS9FLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHFDQUFxQyxDQUFDO0FBQ3pFLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUNqRSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxtQ0FBbUMsQ0FBQztBQUNyRSxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBRWpDLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUUzQyxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQU0zRCxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQ2pDLE9BQU8sRUFBRSxLQUFLLEVBQXdCLEtBQUssRUFBRSxPQUFPLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFFekU7Ozs7O2tJQUtrSTtBQUNsSSxNQUFNLE9BQU8sUUFBUTtJQUNaLE1BQU0sQ0FBQyxhQUFhLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQ2xELE1BQU0sQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDO0lBQ3JCLE1BQU0sS0FBSyxJQUFJO1FBQ2QsT0FBTyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ2hDLENBQUM7SUFFRCxzQ0FBc0M7SUFDN0IsSUFBSSxDQUFlO0lBRTVCLHlGQUF5RjtJQUNoRixLQUFLLENBQWM7SUFFNUIsa0ZBQWtGO0lBQ3pFLEtBQUssQ0FBYztJQUU1QjtnQkFDWTtJQUNILFNBQVMsQ0FBWTtJ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
Line truncated
|
||||
Reference in new issue
Block a user