DigiPress

Highly Flexible WordPress Theme

円弧に沿って回転するテキストのアニメーション要素の作成方法

Webデザイン関連トピック
円弧に沿って回転するテキストのアニメーション要素の作成方法

今回は、SVG パスを使って円弧に沿ったテキストを表示し、そのテキストをアニメーションで回転させる実装方法を、汎用性を前提にして考えてみます。
ここで紹介する SVG コンテンツは、例えばロゴ、バッジ、装飾要素など様々なデザインに活用することを想定しています。

まずは、今回作成するコンテンツのデモをご覧ください。

完成デモ

See the Pen Curve Text on SVG Path by digistate (@digistate) on CodePen.

1. 基本構造と仕組み

まず、このSVGテキスト実装の基本的な仕組みを説明します。

HTML
<div class="curve-text">
<svg viewBox="0 0 100 100">
<!-- 円弧のパス定義 -->
<path id="curve" d="M 0 50 A 50 50 0 1 1 0 50.5 z" fill="transparent"></path>

<!-- 回転するテキスト -->
<g class="rotating-text">
<text class="outer" dy="-0.8em">
<textPath href="#curve" textLength="310" xml:space="preserve" startOffset="2">
Best Luxury Interior Design Trends...
</textPath>
</text>
</g>

<!-- 中央のテキスト -->
<text class="inner" x="50" y="50" text-anchor="middle" dominant-baseline="middle">
<!-- テキスト内容 -->
</text>
<!-- 装飾線 -->
<g>
<line class="divider" x1="25" y1="50" x2="75" y2="50"></line>
<circle class="divider-dot" cx="50" cy="50" r="1"></circle>
</g>
</svg>
</div>

ポイント

SVGの座標系

viewBox="0 0 100 100"で100×100の座標系を定義し、中心は(50, 50)になります。

パス(円弧)の定義

d="M 0 50 A 50 50 0 1 1 0 50.5 z"は半径50の円弧を定義しています。

この円弧は viewBox=”0 0 100 100″ を前提としたものです。

テキストパス

textPath要素がhref="#curve"でパスを参照し、テキストをパスに沿って配置します。

2. CSS 変数による汎用性を考慮したカスタマイズ

今回のサンプルの特徴は、CSS変数(カスタムプロパティ)を活用して様々な要素を簡単にカスタマイズできる点です。
CSS には以下のように CSS 変数を用意しています。

CSSCSS 変数
// カスタマイズ対象の初期値
.curve-text {
--color: #ccc; /* パスと文字のカラー */
--outer-font-size: 11px; /* 外側のフォントサイズ */
--inner-font-size: 30px; /* 円内のフォントサイズ */
--display-size: 200px; /* 実際の表示サイズ */
--svg-size: 200; /* 表示サイズ(pxなし) */
--svg-base-size: 100; /* viewBoxのサイズ */
--rotation-speed: 20s; /* 回転速度 */
--rotation-direction: normal; /* 回転方向 */
--scale-factor: calc(var(--svg-size) / var(--svg-base-size));

/* 以下省略 */
}

CSS 変数の役割と使い方

–color

この CSS 変数のプロパティの値に HEX 値などのカラーコードを渡すことでテキストやパスの色を一括で変更できます。

–display-size

この要素自体の表示サイズを指定します(幅と高さ両方に適用)。

この変数は width, height の値として渡すため、ピクセル(px)単位付きで指定します。

–svg-size

--display-size と同じ数字を、単位を除いた数値で指定します(例: 200)。

この変数は、--display-size が viewBox に対する割合を算出するための --scale-factor を割り出すために必要です。

–outer-font-size

円弧に沿って回転するテキストのフォントサイズを指定します(例: 11px)。

–inner-font-size

円弧内に表示するテキストのフォントサイズを指定します(例: 30px)。

–rotation-speed

アニメーションの速度を秒単位で指定します(例: 20s)。

–rotation-direction

normal(時計回り)またはreverse(反時計回り)を指定します。

これらの変数は、HTMLのインラインスタイルで簡単に上書きできます:

<div class="curve-text" style="--display-size:300px; --color:#ff0000; --rotation-speed:15s;">
<!-- ここにSVG -->
</div>

3. 自動スケーリングの仕組み

SVG のサイズ変更時に文字や線の太さが適切にスケーリングされる仕組みは、このサンプルの重要なポイントとなります。

--scale-factor: calc(var(--svg-size) / var(--svg-base-size));

// 外周(円弧)のテキスト
text.outer {
font-size: calc(var(--outer-font-size) / var(--scale-factor));
}
// 円弧内のテキスト
text.inner {
font-size: calc(var(--inner-font-size) / var(--scale-factor));
}

スケーリングの解説

–scale-factor

SVGの実際のサイズ(--svg-size)とベースサイズ(--svg-base-size)の比率を計算します。

フォントサイズの計算

フォントサイズをスケールファクターで割ることで、表示サイズ(--display-size)が変わっても文字の相対的な大きさが維持されます。

vector-effect: non-scaling-stroke

パスやラインの太さが SVG のサイズ変更に影響されないようにします。

これにより、SVG のサイズを変更しても、すべての要素が適切な比率で表示されます。

4. テキストパスの調整

円弧に沿ったテキストの配置は、細かい調整や配慮が必要となります。

<textPath href="#curve" textLength="310" xml:space="preserve" startOffset="2" lengthAdjust="spacing">
Best Luxury Interior Design Trends and Innovative Decoration Ideas
</textPath>

重要な属性

textPath に指定している各属性は以下の役割があります。

textLength=”310″

テキストの全体の長さを指定します。

円周の長さ(2πr = 2×3.14×50 ≈ 314)より少し短くすることで、テキストの始点と終点に余白をとり、1文字目と最後の文字の間の間隔がなくならないようにしています。

xml:space=”preserve”

テキスト内の空白を保持します。

vector-effect: non-scaling-stroke

パスやラインの太さが SVG のサイズ変更に影響されないようにします。

startOffset=”2″

テキストの開始位置をパスの始点から少しずらします。

lengthAdjust=”spacing”

テキストの長さを調整する際、文字間のスペースのみを調整し、文字自体の幅は変更しません。

テキストの文字数の調整

テキストが長い場合は文字間が詰まり、短い場合は文字間が空いた状態で自動で調整されます。

適切な文字数を定める目安
  • パスの長さを計算(円周 = 2πr)
  • テキストの量に応じて、その値より少し小さい値を設定
  • 視覚的に確認しながら微調整

5. アニメーションの実装

テキストの回転アニメーションは、CSS アニメーションで実装しています。

.rotating-text {
transform-origin: 50px 50px; /* viewBoxの中心 */
animation: rotate var(--rotation-speed) linear infinite;
animation-direction: var(--rotation-direction);
}

// 反時計回りに回転するキーフレーム
@keyframes rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(-360deg);
}
}

アニメーション(回転テキスト)のポイント

transform-origin: 50px 50px

回転の中心点を SVG の中心に設定。

animation: rotate var(–rotation-speed) linear infinite

linear: 一定の速度で回転

infinite: アニメーションを無限に繰り返す

animation-direction: var(–rotation-direction)

回転方向を変数で制御(normal or reverse)。

回転方向を変更するには、キーフレームの値を調整するか、--rotation-direction変数をreverseに設定します。

6. 円弧内の中央テキストの配置

中央のテキストを正確に配置するには、SVGのテキスト配置属性を理解する必要があります。

<text class="inner" x="50" y="50" text-anchor="middle" dominant-baseline="middle">
<tspan x="50" dx="0.14em" dy="-0.72em">INTERIOR</tspan>
<tspan x="50" dy="1.6em">2026</tspan>
</text>

複数行のテキストを中央に配置する場合、最初の行を上に、次の行を下に移動させることで、全体が中央に配置されるようにします。

テキスト配置のポイント

text-anchor=”middle”

テキストを水平方向に中央揃え。

dominant-baseline=”middle”

テキストを垂直方向に中央揃え。

tspan 要素

複数行のテキストを配置するために使用。

dy=”-0.72em”, dy=”1.6em”

行間の微調整(相対的な単位emを使用)。

実際の SVG テキストの表示は、位置が正確(中心)でない場合があるため、その場合のみ目視しながらこれらのプロパティ(dx, dy)を使用して微調整しています。

7. 装飾線のアニメーション

今回のデモでは、円弧内の2行のテキストの間にライン(.divider)を表示しています。
この中央の装飾線には、表示時にフェードインアニメーションを適用しています。

.divider {
stroke: var(--color);
stroke-width: 0.5px;
vector-effect: non-scaling-stroke;
transform: scaleX(0);
transform-origin: center;
animation: fadeInLine 1.2s ease-out .3s forwards;
}

// 中心から左右にラインが伸びるアニメーション
@keyframes fadeInLine {
0% {
transform: scaleX(0);
}
100% {
transform: scaleX(1);
}
}

アニメーションの解説

transform: scaleX(0)

初期状態では線が見えない(幅が 0)。

transform-origin: center

中央から拡大。

animation: fadeInLine 1.2s ease-out .3s forwards

1.2s: アニメーション時間

ease-out: 終わりに向かって徐々に遅くなる

.3s: 0.3秒の遅延後に開始

forwards: アニメーション終了後も最終状態を維持

[おまけ]中央テキストを縦書きで表示

中央のテキストを縦書きにする場合は、text 要素に CSS で writing-mode: vertical-rl または writing-mode: tb を追加し、x, y, dx, dy の基準を横書きのときと逆にして微調整します。

縦書きの場合サンプル

See the Pen Curve Vertical Text on SVG Path by digistate (@digistate) on CodePen.

まとめ

SVG を使った円弧に沿ったテキストの実装は、CSS 変数と SVG の特性を活用することで、柔軟にある程度カスタマイズ可能なデザイン要素を作成できます。

サンプルのポイント
  1. SVG のパスとテキストパスを使用して円弧に沿ったテキストを配置
  2. CSS 変数による汎用性を考慮した構造
  3. スケールファクターを使用した適切なサイズ調整
  4. CSS アニメーションによる回転効果
  5. 中央テキストの正確な配置(微調整)

今後、これをベースにしたカスタムブロックを「DigiPress Ex – Blocks」プラグインに追加してみようと思います。

Share / Subscribe
Facebook
Posts
Hatena Bookmarks
Pinterest
Pocket
Feedly
Send to LINE
AAAWgmp1bWIAAAAeanVtZGMycGEAEQAQgAAAqgA4m3EDYzJwYQAAABZcanVtYgAAAEdqdW1kYzJtYQARABCAAACqADibcQN1cm46YzJwYTo3MmI1NmY0Mi1mOTkxLTRhZWMtYjI3Zi05NmQ2Y2Q2ZGJmZWIAAAADl2p1bWIAAAApanVtZGMyYXMAEQAQgAAAqgA4m3EDYzJwYS5hc3NlcnRpb25zAAAAALxqdW1iAAAARGp1bWRjYm9yABEAEIAAAKoAOJtxE2MycGEuaW5ncmVkaWVudC52MwAAAAAYYzJzaJpFkg1UlHpZNlVv23V+twUAAABwY2JvcqNpZGM6Zm9ybWF0bWltYWdlL3N2Zyt4bWxqaW5zdGFuY2VJRHgseG1wOmlpZDpiYjI4ZjNiNS02YWYyLTQzZDAtOTdhYi05Y2U4N2E3MzNlMGFscmVsYXRpb25zaGlwaHBhcmVudE9mAAAB4mp1bWIAAABBanVtZGNib3IAEQAQgAAAqgA4m3ETYzJwYS5hY3Rpb25zLnYyAAAAABhjMnNo5gNfqq3PzirY5Ex0DoWaEwAAAZljYm9yomdhY3Rpb25zgqJmYWN0aW9ua2MycGEub3BlbmVkanBhcmFtZXRlcnOha2luZ3JlZGllbnRzgaJjdXJseC1zZWxmI2p1bWJmPWMycGEuYXNzZXJ0aW9ucy9jMnBhLmluZ3JlZGllbnQudjNkaGFzaFggRmYWoSvnUaiaZo0ZsQM96LtvWKoYvEtwD1ZLsm7yrrekZmFjdGlvbngdY29tLmFudGhyb3BpYy5jbGF1ZGUucHJvdmlkZWRqcGFyYW1ldGVyc6F4H2NvbS5hbnRocm9waWMub3JpZ2luLWNvbmZpZGVuY2VndW5rbm93bmtkZXNjcmlwdGlvbnhmQ2xhdWRlIHByb3ZpZGVkIHRoaXMgZmlsZSBhdCB0aGUgcmVxdWVzdCBvZiBhIHVzZXIgYW5kIG1heSBoYXZlIGNyZWF0ZWQgb3IgbW9kaWZpZWQgdGhlIGZpbGUgY29udGVudHMubXNvZnR3YXJlQWdlbnShZG5hbWVmQ2xhdWRlcmFsbEFjdGlvbnNJbmNsdWRlZPUAAADIanVtYgAAAEBqdW1kY2JvcgARABCAAACqADibcRNjMnBhLmhhc2guZGF0YQAAAAAYYzJzaKpVotd9NvpSskj5KUcCIi0AAACAY2JvcqVjYWxnZnNoYTI1NmNwYWRNAAAAAAAAAAAAAAAAAGRoYXNoWCAosBvMqF1+lZe9gmOcHC/J3Y6+rBHLvQJxpFh59mfTKGRuYW1lbmp1bWJmIG1hbmlmZXN0amV4Y2x1c2lvbnOBomVzdGFydBjaZmxlbmd0aBkeBAAAAj5qdW1iAAAAJ2p1bWRjMmNsABEAEIAAAKoAOJtxA2MycGEuY2xhaW0udjIAAAACD2Nib3KlY2FsZ2ZzaGEyNTZpc2lnbmF0dXJleE1zZWxmI2p1bWJmPS9jMnBhL3VybjpjMnBhOjcyYjU2ZjQyLWY5OTEtNGFlYy1iMjdmLTk2ZDZjZDZkYmZlYi9jMnBhLnNpZ25hdHVyZWppbnN0YW5jZUlEeCx4bXA6aWlkOjM2MjQxODYwLTVjZjQtNGFiNy1iMTdkLTgzY2I1NGQ4Mjk1Y3JjcmVhdGVkX2Fzc2VydGlvbnODomN1cmx4LXNlbGYjanVtYmY9YzJwYS5hc3NlcnRpb25zL2MycGEuaW5ncmVkaWVudC52M2RoYXNoWCBGZhahK+dRqJpmjRmxAz3ou29Yqhi8S3APVkuybvKut6JjdXJseCpzZWxmI2p1bWJmPWMycGEuYXNzZXJ0aW9ucy9jMnBhLmFjdGlvbnMudjJkaGFzaFggGA0lysfzsAP33kpMa/AM72oz/8ZsEHu9XyDWwTO5v22iY3VybHgpc2VsZiNqdW1iZj1jMnBhLmFzc2VydGlvbnMvYzJwYS5oYXNoLmRhdGFkaGFzaFggLW0SxOkC51fl8mcYUAJVo/Rm2FBikfsY/PunAD9daDd0Y2xhaW1fZ2VuZXJhdG9yX2luZm+jZG5hbWVvQW50aHJvcGljIEZpbGVzZ3ZlcnNpb25lMS4wLjBrc3BlY1ZlcnNpb25lMi40LjAAABA4anVtYgAAAChqdW1kYzJjcwARABCAAACqADibcQNjMnBhLnNpZ25hdHVyZQAAABAIY2JvctKEWQISogEmGCFZAgowggIGMIIBjaADAgECAhRA5aAK7sI50L64g/oGQgU9Z1UTADAKBggqhkjOPQQDAzBJMRcwFQYDVQQKEw5BbnRocm9waWMsIFBCQzEuMCwGA1UEAxMlQW50aHJvcGljIENvbnRlbnQgQ3JlZGVudGlhbHMgUm9vdCBDQTAeFw0yNjA4MDcxODQzNTZaFw0yODA4MDYxOTQzNTZaMEQxFzAVBgNVBAoTDkFudGhyb3BpYywgUEJDMSkwJwYDVQQDEyBBbnRocm9waWMgQ2xhdWRlIENvbnRlbnQgU2lnbmluZzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJh6CmvLUBgFFNU0vUKlOVtE6djd17L5SuwX0LemFisBM3dkd/3cyjxFA3Qo5S46fX0/ihY0VZ7mfb9KF703t5OjWDBWMA4GA1UdDwEB/wQEAwIHgDAVBgNVHSUEDjAMBgorBgEEAYPoXgIBMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUzlHiBIFOZFsj+OPEz5o+nMHXXMIwCgYIKoZIzj0EAwMDZwAwZAIwMXMdFJ4BetLLVY7ORuE9noqbbAZOZn/aArXyTwFAZfKrPzxF2vPoJNf1+UCdg1XGAjBwX1zd9WGqYkqmL5SFqw1QySjr1zJfpJM9+1rdDwSPLMOPOjKuiXjoU/pUUeG9RwmhY3BhZFkNngAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPZYQOX0HxJBDEy+kPFgsqx5au8boT29bL+Ruh52/5DgQoYrU+ZyLgBowbwVTBBjsXdI/XKzdHkn4W7kxyR1u/Wk548=