Vendor globe.gl and its Earth textures

globe.gl 2.46.2 (MIT, three.js r185 bundled) and the NASA Blue Marble
and Black Marble textures from three-globe 2.45.3, copied once from the
npm registry; SOURCES.md records versions, licences and sha256, and the
bundled libraries' notices are in LICENSES-bundled.txt. The service
worker leaves the folder out of the offline precache: the feed loads it
the first time it shows the globe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
This commit is contained in:
thepraandClaude Opus 5.5 committed 2026-10-04 11:03:14 +02:00
1 parent b9040bbd80
commit f41ebf2160
26 files changed
+122 -1101

No files matched your search

-106
View File
@@ -1,106 +0,0 @@
@inherits LocalizableComponentBase
<section class="flex flex-col gap-4">
@if (isPosting)
{
<div class="block p-3 md:p-4 rounded-xl neo-raised neo-xs">
<MessageUpsertForm OnMessageSubmit="OnMessageSubmit" />
</div>
}
<div class="flex justify-between gap-3">
<EditForm Model="Filters">
<div class="flex flex-row gap-3">
@if (OnTimelineChanged.HasDelegate)
{
<DSelect TValue="TimelineType" class="w-auto" Value="Filters.TimelineType"
ValueChanged="async v => await OnTimelineChange(v)" ValueExpression="() => Filters.TimelineType">
<Prefix>
<i class="@Filters.TimelineType.GetTimelineTypeIcon()"></i>
</Prefix>
<ChildContent>
@foreach (var timelineType in Enum.GetValues<TimelineType>())
{
<option value="@timelineType">@Localizer[timelineType.ToString()]</option>
}
</ChildContent>
</DSelect>
}
@if (OnTimeSortingChanged.HasDelegate)
{
<DSelect TValue="TimeSortingType" class="w-auto" Value="Filters.TimeSortingType"
ValueChanged="async v => await OnTimeSortChange(v)" ValueExpression="() => Filters.TimeSortingType">
<Prefix>
<i class="ion-md-funnel"></i>
</Prefix>
<ChildContent>
@foreach (var timeSortingType in Enum.GetValues<TimeSortingType>())
{
<option value="@timeSortingType">@Localizer[timeSortingType.ToString()]</option>
}
</ChildContent>
</DSelect>
}
</div>
</EditForm>
@if (OnMessageSubmit.HasDelegate)
{
<div>
<DButton Active="isPosting" OnClick="OpenCloseMessageForm">
<i class="ion-md-create"></i>
<span>@Localizer["Post"]</span>
</DButton>
</div>
}
else
{
<div></div>
}
</div>
</section>
@code {
[Parameter] public EventCallback<MessageForm> OnMessageSubmit { get; set; }
[Parameter] public EventCallback<TimelineType> OnTimelineChanged { get; set; }
[Parameter] public EventCallback<TimeSortingType> OnTimeSortingChanged { get; set; }
[Inject] ILocalStorageService LocalStorage { get; set; }
bool isPosting;
ActionBarFilter Filters { get; set; } = new();
protected override async Task OnInitializedAsync()
{
var filters = await LocalStorage.GetItemAsync<ActionBarFilter>(nameof(ActionBarFilter));
IsLoading = false;
if (filters is not null)
{
Filters = filters;
return;
}
await LocalStorage.SetItemAsync(nameof(ActionBarFilter), Filters);
}
void OpenCloseMessageForm()
{
isPosting = !isPosting;
}
async Task OnTimelineChange(TimelineType timelineType)
{
Filters.TimelineType = timelineType;
await LocalStorage.SetItemAsync(nameof(ActionBarFilter), Filters);
await OnTimelineChanged.InvokeAsync(Filters.TimelineType);
}
async Task OnTimeSortChange(TimeSortingType timeSorting)
{
Filters.TimeSortingType = timeSorting;
await LocalStorage.SetItemAsync(nameof(ActionBarFilter), Filters);
await OnTimeSortingChanged.InvokeAsync(Filters.TimeSortingType);
}
}
-352
View File
@@ -1,352 +0,0 @@
@inherits LocalizableComponentBase
<EditForm Model="MessageForm" OnValidSubmit="OnValidSubmit">
<DataAnnotationsValidator />
<div class="flex flex-col mb-3">
<DInput TValue="string" class="w-full rounded-t-[1.4rem] rounded-b-lg" maxlength="64" autocomplete="off"
placeholder="@Localizer["Title (optional)"]" Value="@MessageForm.Title"
ValueChanged="(v) => OnTitleChanged(v)"
ValueExpression="() => MessageForm.Title" />
<div class="relative mt-1">
<DTextarea TValue="string" @bind-Value="MessageForm.Content" Immediate="true"
class="w-full rounded-b-[1.4rem] rounded-t-lg" maxlength="@MaxContentLength" autocomplete="off"
placeholder="@Localizer["oh shit... here we go again"]" rows="3" />
<span class="absolute text-xs opacity-50 right-2 bottom-1">@ContentLength/@MaxContentLength</span>
</div>
@if (showPreviewButton && isPreviewOpen && MessageForm.Content is { Length: > 0 })
{
<div class="relative mt-1 px-8">
<div class="neo-inset neo-xs rounded-t-lg rounded-b-[1.4rem] px-2 py-1 md:px-3 md:py-2 text-xs md:text-sm">
@switch (MessageForm.ContentType)
{
case ContentType.Markdown:
@((MarkupString)Markdown.ToHtml(MessageForm.Content))
break;
case ContentType.HTML:
<p>@((MarkupString)MessageForm.Content)</p>
break;
}
</div>
</div>
}
</div>
<div class="flex flex-col gap-3 mb-3 @SUtility.IfTrueThen(MessageForm.Media.Count == 0, "hidden")">
@foreach (var media in MessageForm.Media)
{
switch (MessageForm.MediaType)
{
case MediaType.Images:
<div class="flex w-full items-center gap-3 rounded-xl p-3 md:p-4 neo-raised neo-2xs">
<img alt="@media.AltText" class="object-cover rounded-lg neo-raised neo-2xs max-h-24 md:max-h-40 max-w-[6rem] md:max-w-[12rem]" src="@media.Base64Preview" />
<div class="flex w-full self-start flex-col justify-between gap-2">
<div class="flex w-full gap-3">
<div class="flex-1">
<p class="text-xs md:text-sm break-all">
<i class="ion-md-image"></i> <b>@media.FileName</b>
</p>
<p class="text-xs break-all">
<i class="ion-md-code"></i> @media.ContentType <i class="ion-md-fitness"></i> @media.Size.GetFileSize(Localizer)
</p>
</div>
<DButton Size="DSize.Sm" class="self-start" OnClick="() => RemoveFile(media)">
<i class="ion-md-trash text-base text-red-400"></i>
</DButton>
</div>
<DTextarea TValue="string" @bind-Value="media.AltText" Size="DSize.Sm" class="w-full rounded-lg!" autocomplete="off"
placeholder="@Localizer["Alternative text"]" rows="1" />
</div>
</div>
break;
case MediaType.Video:
case MediaType.Documents:
<div class="flex items-center gap-3 rounded-xl p-3 md:p-4 neo-raised neo-2xs">
<span>
<i class="text-2xl @MessageForm.MediaType.GetMediaTypeIcon()"></i>
</span>
<div class="flex flex-col w-full gap-1">
<p class="text-xs md:text-sm break-all">
<b>@media.FileName</b>
</p>
<p class="text-xs break-all">
<i class="ion-md-code"></i> @media.ContentType <i class="ion-md-fitness"></i> @media.Size.GetFileSize(Localizer)
</p>
</div>
<DButton Size="DSize.Sm" OnClick="() => RemoveFile(media)">
<i class="ion-md-trash text-base text-red-400"></i>
</DButton>
</div>
break;
case MediaType.Audio:
<div class="flex items-center gap-3 rounded-xl p-3 md:p-4 neo-raised neo-2xs">
<span>
<i class="text-2xl @MessageForm.MediaType.GetMediaTypeIcon()"></i>
</span>
<div class="flex flex-col w-full gap-1">
<p class="text-xs md:text-sm break-all">
<b>@media.FileName</b>
</p>
<p class="text-xs break-all">
<i class="ion-md-code"></i> @media.ContentType <i class="ion-md-fitness"></i> @media.Size.GetFileSize(Localizer)
</p>
<audio controls="controls" class="w-full max-h-8">
<source src="@media.Base64Preview" type="@media.ContentType">
</audio>
</div>
<DButton Size="DSize.Sm" OnClick="() => RemoveFile(media)">
<i class="ion-md-trash text-base text-red-400"></i>
</DButton>
</div>
break;
}
}
</div>
<ErrorViewer ContainerClass="mb-3" AdditionalError="@contentError" AdditionalErrors="fileErrors" />
<div class="flex flex-wrap items-start justify-between gap-3">
<div class="flex flex-wrap items-start gap-3">
<DDropdown @bind-IsOpen="MessageForm.IsScopeOptionsOpen"
TriggerClass="@(MessageForm.IsScopeOptionsOpen ? "btn btn-sm btn-active" : "btn btn-sm")"
ContentClass="mt-2 flex gap-2 p-2 rounded-box"
title="@Localizer["Message scope type: {0}", Localizer[MessageForm.MessageType.ToString()]]">
<Trigger>
<i class="@MessageForm.MessageType.GetMessageTypeIcon() text-base"></i>
</Trigger>
<ChildContent>
<DButton Size="DSize.Sm" Active="MessageForm.MessageType is MessageType.Direct" OnClick="() => UpdateMessageType(MessageType.Direct)"
title="@Localizer[MessageType.Direct.ToString()]">
<i class="ion-md-paper-plane text-base"></i>
</DButton>
<DButton Size="DSize.Sm" Active="MessageForm.MessageType is MessageType.FollowersOnly" OnClick="() => UpdateMessageType(MessageType.FollowersOnly)"
title="@Localizer[MessageType.FollowersOnly.ToString()]">
<i class="ion-md-lock text-base"></i>
</DButton>
<DButton Size="DSize.Sm" Active="MessageForm.MessageType is MessageType.Unlisted" OnClick="() => UpdateMessageType(MessageType.Unlisted)"
title="@Localizer[MessageType.Unlisted.ToString()]">
<i class="ion-md-unlock text-base"></i>
</DButton>
<DButton Size="DSize.Sm" Active="MessageForm.MessageType is MessageType.Public" OnClick="() => UpdateMessageType(MessageType.Public)"
title="@Localizer[MessageType.Public.ToString()]">
<i class="ion-md-globe text-base"></i>
</DButton>
</ChildContent>
</DDropdown>
@* A label styled as a button opens the hidden file input. *@
<label class="btn btn-sm @SUtility.IfTrueThen(ShouldDisableUpload(), "btn-disabled")">
<InputFile accept="@acceptedFilesTypes" class="hidden" multiple="@ShouldHaveMultipleUpload()" OnChange="OnFileChange" disabled="@ShouldDisableUpload()" />
<i class="ion-md-attach text-base"></i>
@if (MessageForm.Media.Count != 0)
{
<span>+@MessageForm.Media.Count</span>
}
</label>
<DSelect TValue="MediaType" Size="DSize.Sm" class="w-auto" Value="MessageForm.MediaType" ValueChanged="v => OnMediaTypeChanged(v)"
ValueExpression="() => MessageForm.MediaType" disabled="@(MessageForm.Media.Count > 0)">
<Prefix>
<i class="@MessageForm.MediaType.GetMediaTypeIcon()"></i>
</Prefix>
<ChildContent>
@foreach (var mediaType in Enum.GetValues<MediaType>())
{
<option value="@mediaType">@Localizer[mediaType.ToString()]</option>
}
</ChildContent>
</DSelect>
<div class="flex flex-col">
<DSelect TValue="ContentType" Size="DSize.Sm" class="w-auto" Value="MessageForm.ContentType" ValueChanged="v => OnContentTypeChanged(v)"
ValueExpression="() => MessageForm.ContentType">
<Prefix>
<i class="@MessageForm.ContentType.GetContentTypeIcon()"></i>
</Prefix>
<ChildContent>
@foreach (var contentType in Enum.GetValues<ContentType>())
{
<option value="@contentType">@Localizer[contentType.ToString()]</option>
}
</ChildContent>
</DSelect>
</div>
@if (showPreviewButton)
{
<DButton Size="DSize.Sm" Active="isPreviewOpen" OnClick="OnOpenClosePreview" title="@Localizer["Show preview"]">
<i class="@SUtility.IfTrueThen(isPreviewOpen, "ion-md-eye-off", "ion-md-eye") text-base"></i>
</DButton>
}
</div>
<DButton Size="DSize.Sm" Type="submit" Disabled="IsDefaultDisabled">
<span>@Localizer["Post"]</span>
<i class="ion-md-send"></i>
</DButton>
</div>
</EditForm>
@code {
const int MaxContentLength = 5_000;
[Inject] ILoggingService Logger { get; set; }
[Parameter] public Message AnsweringMessage { get; set; }
[Parameter] public EventCallback<MessageForm> OnMessageSubmit { get; set; }
MessageForm MessageForm { get; set; } = new();
List<string> fileErrors = [];
string contentError;
string acceptedFilesTypes = ".jpg,.jpeg,.png,.gif";
bool showPreviewButton;
bool isPreviewOpen;
// Content is null until the user types: a form starts without text.
int ContentLength => MessageForm.Content?.Length ?? 0;
int MaximumFileCount => MessageForm.MediaType switch
{
MediaType.Images => 5,
MediaType.Video or MediaType.Audio => 1,
MediaType.Documents => 3,
_ => 0
};
long MaximumFileSize => MessageForm.MediaType switch
{
MediaType.Images or MediaType.Documents => 3_145_728,
MediaType.Audio => 5_242_880,
MediaType.Video => 20_971_520,
_ => 0
};
protected override void OnInitialized()
{
IsLoading = false;
if (AnsweringMessage is null)
return;
MessageForm.Title = AnsweringMessage.Title;
MessageForm.RootMessageId = AnsweringMessage.RootMessageId ?? AnsweringMessage.MessageId;
}
void UpdateMessageType(MessageType messageType)
{
MessageForm.MessageType = messageType;
MessageForm.IsScopeOptionsOpen = false;
}
bool ShouldDisableUpload() => MessageForm.Media.Count >= MaximumFileCount;
bool ShouldHaveMultipleUpload() => MessageForm.MediaType is MediaType.Images or MediaType.Documents;
async Task OnFileChange(InputFileChangeEventArgs eventArgs)
{
fileErrors = [];
var maximumFileCount = MaximumFileCount;
if (eventArgs.FileCount + MessageForm.Media.Count > maximumFileCount)
{
fileErrors.Add(Localizer["The maximum number of files accepted is {0}, but {1} were supplied.", maximumFileCount,
MessageForm.Media.Count + eventArgs.FileCount]);
return;
}
var maximumFileSize = MaximumFileSize;
foreach (var file in eventArgs.GetMultipleFiles(maximumFileCount))
{
if (file.Name == default || file.ContentType == default || MessageForm.Media.Any(m => m.FileName == file.Name))
continue;
if (file.Size > maximumFileSize)
{
fileErrors.Add(Localizer["Supplied file \"{0}\" with size {1} exceeds the maximum of {2}.", file.Name,
file.Size.GetFileSize(Localizer), maximumFileSize.GetFileSize(Localizer)]);
continue;
}
var uploadMedia = await ReadFile(file, maximumFileSize);
if (uploadMedia is null)
{
fileErrors.Add(Localizer["The file \"{0}\" could not be read.", file.Name]);
continue;
}
MessageForm.Media.Add(uploadMedia);
}
}
/// <summary>Reads a picked file into memory; null when the browser can't read it (logged).</summary>
async Task<UploadMedia> ReadFile(IBrowserFile file, long maximumFileSize, CancellationToken cancellationToken = default)
{
try
{
using var memoryStream = new MemoryStream();
await using var fileStream = file.OpenReadStream(maximumFileSize, cancellationToken);
await fileStream.CopyToAsync(memoryStream, cancellationToken);
var uploadMedia = new UploadMedia
{
FileName = file.Name,
ContentType = file.ContentType,
Size = file.Size,
Blob = memoryStream.ToArray()
};
if (MessageForm.MediaType is MediaType.Images or MediaType.Audio)
uploadMedia.Base64Preview = $"data:{uploadMedia.ContentType};base64,{Convert.ToBase64String(uploadMedia.Blob)}";
return uploadMedia;
}
catch (Exception ex)
{
await Logger.ProcessError(ex, $"{nameof(MessageUpsertForm)}.{nameof(ReadFile)}:{file.Name}", cancellationToken);
return default;
}
}
void RemoveFile(UploadMedia media)
{
MessageForm.Media.Remove(media);
}
void OnTitleChanged(string value)
{
MessageForm.Title = value;
}
void OnContentTypeChanged(ContentType contentType)
{
MessageForm.ContentType = contentType;
showPreviewButton = contentType is ContentType.Markdown or ContentType.HTML;
}
void OnMediaTypeChanged(MediaType mediaType)
{
MessageForm.MediaType = mediaType;
acceptedFilesTypes = mediaType switch
{
MediaType.Images => ".jpg,.jpeg,.png,.gif",
MediaType.Video => ".webm,.mp4,.m4v",
MediaType.Audio => ".mp3,.wav,.flac,.m4a",
MediaType.Documents => ".xlsx,.csv,.ppt,.odt",
_ => default
};
}
void OnOpenClosePreview()
{
isPreviewOpen = !isPreviewOpen;
}
async Task OnValidSubmit()
{
contentError = default;
if (string.IsNullOrWhiteSpace(MessageForm.Content) && MessageForm.Media.Count == 0)
{
contentError = Localizer["Missing content, either message or media"];
return;
}
await OnMessageSubmit.InvokeAsync(MessageForm);
}
}
-297
View File
@@ -1,297 +0,0 @@
using decePubClient.Models;
using decePubClient.Models.Types;
using Markdig;
namespace decePubClient.Helpers;
/// <summary>
/// Mock data until the app is wired to PrivaPub: the signed-in user, the feed shown while IndexedDB holds no messages,
/// and the thread around an expanded message.
/// </summary>
public static class Faker
{
public static User CurrentUser => new()
{
Id = "45f14fa8-c40f-4121-997c-ef2542196a50",
UserName = "@loosy@letsrulethe.world",
DisplayName = "loosy",
PictureUrl = "https://letsrulethe.world/media/ddd91d51-dc12-4b82-86a2-2a28cc959183/L51ZAL4QEL07",
BackgroundUrl = "https://letsrulethe.world/media/9a3cc6c4-1018-4f41-86c7-f3e63e362bf4/EXM8RUK10B0Z",
ProfileUrl = "https://letsrulethe.world/users/loosy"
};
static IReadOnlyList<MessageUser> Users =>
[
CurrentUser.ToMessageUser(),
new()
{
UserId = "7b5703dc-aee8-46b1-aed2-cd06021a1c0c",
DisplayName = "loweel",
UserName = "@loweel@bbs.keinpfusch.net",
PictureUrl = "https://ipfs.keinpfusch.net/ipfs/bafybeiazrrmngqww7mfag76gmcmw6l2nohckuh6yvldbzatkls5yyznxb4?name=Yb7peXARjY3B_A.png",
BackgroundUrl = "https://ipfs.keinpfusch.net/ipfs/bafkreialv6avp3xykmfc75daevjz4k3chd27eop7o62nznafy46pwjpd2y?name=QBZNoDonJ1HvEw.jpg",
ProfileUrl = "https://letsrulethe.world/users/AG6rE2nRya826QEJFY"
},
new()
{
UserId = "bc9c2a2b-fc5f-42fc-b907-ac30203eed45",
DisplayName = "Valentina Nappi",
UserName = "@valentina.nappi@mastodon.uno",
PictureUrl = "https://s-media-cache-ak0.pinimg.com/564x/a0/30/00/a030003d2e506ec9731b8460127d15f9.jpg",
BackgroundUrl = "https://wallup.net/wp-content/uploads/2016/01/225560-nature-landscape-fall-path-forest-mist-morning-trees-leaves-sunlight.jpg",
ProfileUrl = "https://mastodon.uno/web/@valenappi@beta.birdsite.live"
}
];
public static MessageUser GetRandomUser()
{
return Users[Random.Shared.Next(0, Users.Count)];
}
public static BoostingUser GetRandomBoostingUser()
{
var user = Users[Random.Shared.Next(0, Users.Count)];
return new()
{
UserId = user.UserId,
DisplayName = user.DisplayName,
UserName = user.UserName,
PictureUrl = user.PictureUrl,
ProfileUrl = user.ProfileUrl
};
}
/// <summary>
/// The seed feed. Two entries share a MessageId on purpose: the second is the first one boosted by someone, which
/// is how the feed shows a boost (a copy of the message with BoostingUser set).
/// </summary>
public static List<Message> SeedMessages()
{
var messages = new List<Message>();
messages.Add(new()
{
RootMessageId = default,
MessageId = "992167EE-8947-4823-B1E2-B4E1019B6974",
User = GetRandomUser(),
MessageType = (MessageType)Random.Shared.Next(0, 4),
Title = default,
Content = "test di messaggio normale senza titolo",
Medias = [],
CreatedAt = DateTime.UtcNow.AddMinutes(Random.Shared.Next(-5000, 0)),
IsFavourite = Random.Shared.Next() % 2 == 0,
BoostsCounter = Random.Shared.Next(0, 100),
IsBoostedByCurrentUser = Random.Shared.Next() % 2 == 0,
});
messages.Add(new()
{
RootMessageId = default,
MessageId = "C5307644-4EA8-4B5F-A240-7CFE4DE34741",
User = GetRandomUser(),
MessageType = (MessageType)Random.Shared.Next(0, 4),
Title = "sopra la panca la capra canta",
Content = Markdown.ToHtml("test di messaggio con titolo"),
Medias = [],
CreatedAt = DateTime.UtcNow.AddMinutes(Random.Shared.Next(-5000, 0)),
IsFavourite = Random.Shared.Next() % 2 == 0,
BoostsCounter = Random.Shared.Next(0, 100),
IsBoostedByCurrentUser = Random.Shared.Next() % 2 == 0,
});
messages.Add(new()
{
RootMessageId = default,
MessageId = "E473D562-D210-4453-93DA-157D4B90B0D8",
User = GetRandomUser(),
MessageType = (MessageType)Random.Shared.Next(0, 4),
Title = default,
Content = "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd test di messaggio con overflow del testo",
Medias = [],
CreatedAt = DateTime.UtcNow.AddMinutes(Random.Shared.Next(-5000, 0)),
IsFavourite = Random.Shared.Next() % 2 == 0,
BoostsCounter = Random.Shared.Next(0, 100),
IsBoostedByCurrentUser = Random.Shared.Next() % 2 == 0,
});
messages.Add(new()
{
RootMessageId = default,
MessageId = "adf89dc6-0484-430e-a7c9-fcb1179b0c28",
User = GetRandomUser(),
MessageType = (MessageType)Random.Shared.Next(0, 4),
Title = default,
Content = "test video",
Medias =
[
new()
{
FileName = "8252d175e714db88beb8ee0349dbac90405d3d5148e96e0cfd7de3b0876dbb1b.mp4",
Url = "https://ihatebeinga.live/media/8252d175e714db88beb8ee0349dbac90405d3d5148e96e0cfd7de3b0876dbb1b.mp4",
AltText = "https://ihatebeinga.live/media/8252d175e714db88beb8ee0349dbac90405d3d5148e96e0cfd7de3b0876dbb1b.mp4",
ContentType = "video/mp4"
}
],
CreatedAt = DateTime.UtcNow.AddMinutes(Random.Shared.Next(-5000, 0)),
IsFavourite = Random.Shared.Next() % 2 == 0,
BoostsCounter = Random.Shared.Next(0, 100),
IsBoostedByCurrentUser = Random.Shared.Next() % 2 == 0,
});
messages.Add(new()
{
RootMessageId = default,
MessageId = "96025b43-5235-44e9-a3fa-98df31edfbfb",
User = GetRandomUser(),
MessageType = (MessageType)Random.Shared.Next(0, 4),
Title = default,
Content = "test immagine",
Medias =
[
new()
{
FileName = "51a7cf620f1dd096ac5867d5b78f8c71d57a23972b31c64ec124a8c41e77a618.jpg",
Url = "https://ihatebeinga.live/media/51a7cf620f1dd096ac5867d5b78f8c71d57a23972b31c64ec124a8c41e77a618.jpg",
AltText = "51a7cf620f1dd096ac5867d5b78f8c71d57a23972b31c64ec124a8c41e77a618.jpg",
ContentType = "image/jpg"
}
],
CreatedAt = DateTime.UtcNow.AddMinutes(Random.Shared.Next(-5000, 0)),
IsFavourite = Random.Shared.Next() % 2 == 0,
BoostsCounter = Random.Shared.Next(0, 100),
IsBoostedByCurrentUser = Random.Shared.Next() % 2 == 0,
});
messages.Add(new()
{
RootMessageId = default,
MessageId = "277ca76b-aaad-4aa6-95fb-25f59e2fddf9",
User = GetRandomUser(),
MessageType = (MessageType)Random.Shared.Next(0, 4),
Title = default,
Content = "test audio",
Medias =
[
new()
{
FileName = "09bfb06d0096975f.mp3",
Url = "https://cdn.masto.host/mastodonuno/media_attachments/files/107/798/288/501/917/857/original/09bfb06d0096975f.mp3",
AltText = "09bfb06d0096975f.mp3",
ContentType = "audio/mp3"
}
],
CreatedAt = DateTime.UtcNow.AddMinutes(Random.Shared.Next(-5000, 0)),
IsFavourite = Random.Shared.Next() % 2 == 0,
BoostsCounter = Random.Shared.Next(0, 100),
IsBoostedByCurrentUser = Random.Shared.Next() % 2 == 0,
});
messages.Add(new()
{
BoostingUser = GetRandomBoostingUser(),
RootMessageId = default,
MessageId = "de64e520-a7d3-4f31-b5a9-ba236f3b146c",
User = GetRandomUser(),
MessageType = (MessageType)Random.Shared.Next(0, 4),
Title = default,
Content = "test immagini",
Medias =
[
new()
{
FileName = "51a7cf620f1dd096ac5867d5b78f8c71d57a23972b31c64ec124a8c41e77a618.jpg",
Url = "https://ihatebeinga.live/media/51a7cf620f1dd096ac5867d5b78f8c71d57a23972b31c64ec124a8c41e77a618.jpg",
AltText = "51a7cf620f1dd096ac5867d5b78f8c71d57a23972b31c64ec124a8c41e77a618.jpg",
ContentType = "image/jpg"
},
new()
{
FileName = "51a7cf620f1dd096ac5867d5b78f8c71d57a23972b31c64ec124a8c41e77a618.jpg",
Url = "https://ihatebeinga.live/media/51a7cf620f1dd096ac5867d5b78f8c71d57a23972b31c64ec124a8c41e77a618.jpg",
AltText = "51a7cf620f1dd096ac5867d5b78f8c71d57a23972b31c64ec124a8c41e77a618.jpg",
ContentType = "image/jpg"
},
new()
{
FileName = "51a7cf620f1dd096ac5867d5b78f8c71d57a23972b31c64ec124a8c41e77a618.jpg",
Url = "https://ihatebeinga.live/media/51a7cf620f1dd096ac5867d5b78f8c71d57a23972b31c64ec124a8c41e77a618.jpg",
AltText = "51a7cf620f1dd096ac5867d5b78f8c71d57a23972b31c64ec124a8c41e77a618.jpg",
ContentType = "image/jpg"
}
],
CreatedAt = DateTime.UtcNow.AddMinutes(Random.Shared.Next(-5000, 0)),
IsFavourite = Random.Shared.Next() % 2 == 0,
BoostsCounter = Random.Shared.Next(0,100),
IsBoostedByCurrentUser = Random.Shared.Next() % 2 == 0,
});
messages.Add(new()
{
RootMessageId = default,
MessageId = "de64e520-a7d3-4f31-b5a9-ba236f3b146c",
User = GetRandomUser(),
MessageType = (MessageType)Random.Shared.Next(0, 4),
Title = default,
Content = "test immagini",
Medias =
[
new()
{
FileName = "51a7cf620f1dd096ac5867d5b78f8c71d57a23972b31c64ec124a8c41e77a618.jpg",
Url = "https://ihatebeinga.live/media/51a7cf620f1dd096ac5867d5b78f8c71d57a23972b31c64ec124a8c41e77a618.jpg",
AltText = "51a7cf620f1dd096ac5867d5b78f8c71d57a23972b31c64ec124a8c41e77a618.jpg",
ContentType = "image/jpg"
},
new()
{
FileName = "51a7cf620f1dd096ac5867d5b78f8c71d57a23972b31c64ec124a8c41e77a618.jpg",
Url = "https://ihatebeinga.live/media/51a7cf620f1dd096ac5867d5b78f8c71d57a23972b31c64ec124a8c41e77a618.jpg",
AltText = "51a7cf620f1dd096ac5867d5b78f8c71d57a23972b31c64ec124a8c41e77a618.jpg",
ContentType = "image/jpg"
},
new()
{
FileName = "51a7cf620f1dd096ac5867d5b78f8c71d57a23972b31c64ec124a8c41e77a618.jpg",
Url = "https://ihatebeinga.live/media/51a7cf620f1dd096ac5867d5b78f8c71d57a23972b31c64ec124a8c41e77a618.jpg",
AltText = "51a7cf620f1dd096ac5867d5b78f8c71d57a23972b31c64ec124a8c41e77a618.jpg",
ContentType = "image/jpg"
}
],
CreatedAt = DateTime.UtcNow.AddMinutes(Random.Shared.Next(-5000, 0)),
IsFavourite = Random.Shared.Next() % 2 == 0,
BoostsCounter = Random.Shared.Next(0,100),
IsBoostedByCurrentUser = Random.Shared.Next() % 2 == 0,
});
return messages;
}
/// <summary>The messages before and after an expanded one.</summary>
public static (List<Message> Ancestors, List<Message> Descendants) Thread(Message message) =>
(
[
new()
{
RootMessageId = default,
MessageId = "51C698E3-7C28-4C90-9212-48D5C81DE089",
User = GetRandomUser(),
MessageType = (MessageType)Random.Shared.Next(0, 4),
Title = message.Title,
Content = "<p>esempio di messaggio <b>precedente</b> a quello espanso</p>",
Medias = [],
CreatedAt = DateTime.UtcNow.AddMinutes(Random.Shared.Next(-5000, 0)),
IsFavourite = Random.Shared.Next() % 2 == 0,
BoostsCounter = Random.Shared.Next(0, 100),
IsBoostedByCurrentUser = Random.Shared.Next() % 2 == 0,
}
],
[
new()
{
RootMessageId = default,
MessageId = "0569A1DF-46FC-4485-9F11-F8CDFB794404",
User = GetRandomUser(),
MessageType = (MessageType)Random.Shared.Next(0, 4),
Title = message.Title,
Content = "<p>esempio di messaggio <b>successivo</b> a quello espanso</p>",
Medias = [],
CreatedAt = DateTime.UtcNow.AddMinutes(Random.Shared.Next(-5000, 0)),
IsFavourite = Random.Shared.Next() % 2 == 0,
BoostsCounter = Random.Shared.Next(0, 100),
IsBoostedByCurrentUser = Random.Shared.Next() % 2 == 0,
}
]
);
}
-9
View File
@@ -1,9 +0,0 @@
using decePubClient.Models.Types;
namespace decePubClient.Models;
public class ActionBarFilter
{
public TimelineType TimelineType { get; set; } = TimelineType.Home;
public TimeSortingType TimeSortingType { get; set; } = TimeSortingType.Ascending;
}
-11
View File
@@ -1,11 +0,0 @@
namespace decePubClient.Models
{
public class BoostingUser
{
public string UserId { get; set; }
public string UserName { get; set; }
public string DisplayName { get; set; }
public string PictureUrl { get; set; }
public string ProfileUrl { get; set; }
}
}
-13
View File
@@ -1,13 +0,0 @@
using System.Security.Principal;
namespace decePubClient.Models
{
public interface CustomIPrincipal : IPrincipal
{
string UserId { get; set; }
string UserName { get; set; }
string DisplayName { get; set; }
string PictureUrl { get; set; }
string ProfileUrl { get; set; }
}
}
-20
View File
@@ -1,20 +0,0 @@
using System.Security.Principal;
namespace decePubClient.Models
{
public class CustomPrincipal : CustomIPrincipal
{
public string UserId { get; set; }
public string UserName { get; set; }
public string DisplayName { get; set; }
public string PictureUrl { get; set; }
public string ProfileUrl { get; set; }
public bool IsAdmin { get; set; } = false;
public IIdentity Identity { get; }
public CustomPrincipal(string userName, string authType) =>
Identity = new GenericIdentity(userName, authType);
public bool IsInRole(string role) => false;
}
}
-11
View File
@@ -1,11 +0,0 @@
namespace decePubClient.Models
{
public class Media
{
public string FileName { get; set; }
public string Url { get; set; }
public string ContentType { get; set; }
public string AltText { get; set; }
public byte[] Blob { get; set; } = []; //TODO TEMPORARY
}
}
-10
View File
@@ -1,10 +0,0 @@
namespace decePubClient.Models
{
public class Mention
{
public string DisplayName { get; set; }
public string UserName { get; set; }
public string UserId { get; set; }
public string ProfileUrl { get; set; }
}
}
-25
View File
@@ -1,25 +0,0 @@
using System.ComponentModel;
using System.Text.Json.Serialization;
using decePubClient.Models.Types;
namespace decePubClient.Models
{
public class Message
{
public MessageUser User { get; set; } = new();
public MessageType MessageType { get; set; } = MessageType.Public;
public string RootMessageId { get; set; }
public string MessageId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public bool IsFavourite { get; set; } = false;
public int BoostsCounter { get; set; } = 0;
public bool IsBoostedByCurrentUser { get; set; } = false;
public BoostingUser BoostingUser { get; set; }
public List<Media> Medias { get; set; } = [];
public DateTime CreatedAt { get; set; }
[Bindable(false), JsonIgnore]
public bool IsOptionsOpen { get; set; } = false;
}
}
-28
View File
@@ -1,28 +0,0 @@
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
using decePubClient.Models.Types;
using decePubClient.Resources;
namespace decePubClient.Models;
public class MessageForm
{
public string RootMessageId { get; set; }
[Required(ErrorMessageResourceName = ValidationNames.Required, ErrorMessageResourceType = typeof(ErrorMessages))]
public MessageType MessageType { get; set; } = MessageType.Public;
[Required(ErrorMessageResourceName = ValidationNames.Required, ErrorMessageResourceType = typeof(ErrorMessages))]
public ContentType ContentType { get; set; } = ContentType.PlainText;
[StringLength(64, ErrorMessageResourceName = ValidationNames.MaxLength, ErrorMessageResourceType = typeof(ErrorMessages))]
public string Title { get; set; }
[StringLength(5_000, ErrorMessageResourceName = ValidationNames.MaxLength, ErrorMessageResourceType = typeof(ErrorMessages))]
public string Content { get; set; }
public List<UploadMedia> Media { get; set; } = [];
[JsonIgnore, Bindable(false)]
public MediaType MediaType { get; set; } = MediaType.Images;
[JsonIgnore, Bindable(false)]
public bool IsScopeOptionsOpen { get; set; } = false;
}
-12
View File
@@ -1,12 +0,0 @@
namespace decePubClient.Models
{
public class MessageUser
{
public string UserId { get; set; }
public string UserName { get; set; }
public string DisplayName { get; set; }
public string PictureUrl { get; set; }
public string BackgroundUrl { get; set; }
public string ProfileUrl { get; set; }
}
}
-8
View File
@@ -1,8 +0,0 @@
namespace decePubClient.Models.Types;
public enum ContentType
{
PlainText = 1,
HTML,
Markdown
}
-7
View File
@@ -1,7 +0,0 @@
namespace decePubClient.Models.Types;
public enum TimeSortingType
{
Ascending,
Descending
}
-40
View File
@@ -1,40 +0,0 @@
namespace decePubClient.Models
{
public class User
{
public string Id { get; set; }
public bool IsAuthenticated { get; set; } = false;
public List<UserClaim> Claims { get; set; } = [];
public string UserName { get; set; }
public string DisplayName { get; set; }
public string PictureUrl { get; set; }
public string BackgroundUrl { get; set; }
public string ProfileUrl { get; set; }
public MessageUser ToMessageUser() => new()
{
UserId = Id,
UserName = UserName,
DisplayName = DisplayName,
PictureUrl = PictureUrl,
BackgroundUrl = BackgroundUrl,
ProfileUrl = ProfileUrl
};
public BoostingUser ToBoostingUser() => new()
{
UserId = Id,
UserName = UserName,
DisplayName = DisplayName,
PictureUrl = PictureUrl,
ProfileUrl = ProfileUrl
};
}
public class UserClaim
{
public string Type { get; set; }
public string Value { get; set; }
}
}
-23
View File
@@ -1,23 +0,0 @@
@page "/authentication/{action}"
@inherits PagesBase
<section class="block relative w-full h-full neo-inset neo-xs rounded-xl">
<div class="flex flex-col gap-4 p-4 md:p-5 w-full h-full absolute overflow-y-auto">
<RemoteAuthenticatorView Action="@Action" />
</div>
</section>
@code {
[Parameter]
public string Action { get; set; }
protected override void OnInitialized()
{
base.OnInitialized();
}
}
@@ -1,19 +0,0 @@
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.Extensions.Options;
namespace decePubClient.Services
{
public class ApiAuthorizationOptionsConfiguration : IPostConfigureOptions<RemoteAuthenticationOptions<ApiAuthorizationProviderOptions>>
{
public void Configure(RemoteAuthenticationOptions<ApiAuthorizationProviderOptions> options)
{
options.UserOptions.RoleClaim ??= "role";
}
public void PostConfigure(string name, RemoteAuthenticationOptions<ApiAuthorizationProviderOptions> options)
{
if (string.Equals(name, Options.DefaultName))
Configure(options);
}
}
}
-88
View File
@@ -1,88 +0,0 @@
using collAnon.Client.Services;
using decePubClient.Extensions;
using decePubClient.Models;
using decePubClient.Models.Types;
using PrivaPub.ClientModels;
namespace decePubClient.Services
{
/// <summary>
/// Message actions. Still a mock: the app isn't wired to PrivaPub yet, so each method builds its result in memory.
/// The signatures are the real ones (a Task&lt;WebResult&gt; whose Data is the updated entity), so wiring means
/// calling httpService against PrivaPub's /clientapi/post/* routes inside the same try/catch, reading failures with
/// ReadWebResult and the body with DefaultReadFromJsonAsync, as b2b.next's StoreService does.
/// </summary>
public class MessagesService(ILoggingService logger, CoalescingStringLocalizer localizer)
{
/// <summary>Posts a message or, with RootMessageId set, a reply; Data is the new Message.</summary>
public Task<WebResult> SubmitMessage(MessageForm messageForm, User author, CancellationToken cancellationToken = default) =>
Run(nameof(SubmitMessage), () => (object)new Message
{
RootMessageId = messageForm.RootMessageId,
MessageId = Guid.NewGuid().ToString(),
Content = messageForm.Content?.ParseContent(messageForm.ContentType),
CreatedAt = DateTime.UtcNow,
MessageType = messageForm.MessageType,
Medias = [.. messageForm.Media.Select(m => new Media
{
FileName = m.FileName,
AltText = m.AltText,
ContentType = m.ContentType,
Url = m.Base64Preview,
Blob = m.Blob
})],
Title = messageForm.Title,
User = author.ToMessageUser()
}, cancellationToken);
/// <summary>Opens a reply of the given scope to a message; Data is the message.</summary>
public Task<WebResult> ReplyMessage(Message messageToReply, MessageType messageType = MessageType.Public, CancellationToken cancellationToken = default) =>
Run(nameof(ReplyMessage), () => messageToReply, cancellationToken);
/// <summary>Boosts the message, or takes the boost back; Data is the message with its counter updated.</summary>
public Task<WebResult> BoostUnboostMessage(Message message, CancellationToken cancellationToken = default) =>
Run(nameof(BoostUnboostMessage), () =>
{
message.BoostsCounter += message.IsBoostedByCurrentUser ? -1 : 1;
message.IsBoostedByCurrentUser = !message.IsBoostedByCurrentUser;
return message;
}, cancellationToken);
/// <summary>Adds the message to the favourites, or removes it; Data is the updated message.</summary>
public Task<WebResult> FavouriteUnfavouriteMessage(Message message, CancellationToken cancellationToken = default) =>
Run(nameof(FavouriteUnfavouriteMessage), () =>
{
message.IsFavourite = !message.IsFavourite;
return message;
}, cancellationToken);
public Task<WebResult> DeleteMessage(Message message, CancellationToken cancellationToken = default) =>
Run(nameof(DeleteMessage), () => message, cancellationToken);
public Task<WebResult> BlockUserFromMessage(MessageUser messageUser, CancellationToken cancellationToken = default) =>
Run(nameof(BlockUserFromMessage), () => messageUser, cancellationToken);
public Task<WebResult> SilenceUserFromMessage(MessageUser messageUser, CancellationToken cancellationToken = default) =>
Run(nameof(SilenceUserFromMessage), () => messageUser, cancellationToken);
/// <summary>The mock's stand-in for an API call: the same success/failure handling, with the outcome built locally.</summary>
async Task<WebResult> Run(string caller, Func<object> action, CancellationToken cancellationToken)
{
var result = new WebResult();
try
{
cancellationToken.ThrowIfCancellationRequested();
await Task.Yield();
result.Data = action();
return result;
}
catch (Exception ex)
{
await logger.ProcessError(ex, $"{nameof(MessagesService)}.{caller}", cancellationToken);
return result.Invalidate(localizer["The action could not be completed."], exception: ex);
}
}
}
}
-21
View File
@@ -1,21 +0,0 @@
@inherits LocalizableComponentBase
<AuthorizeView>
<Authorized>
<DButton OnClick="BeginSignOut">
@Localizer["Logout"]
</DButton>
</Authorized>
<NotAuthorized>
<NavLink ActiveClass="btn-active" class="btn" href="authentication/login">
@Localizer["Login"]
</NavLink>
</NotAuthorized>
</AuthorizeView>
@code {
private void BeginSignOut(MouseEventArgs args)
{
Navigation.NavigateTo("logout");
}
}
+2 -1
View File
@@ -9,7 +9,8 @@ self.addEventListener('fetch', event => event.respondWith(onFetch(event)));
const cacheNamePrefix = 'offline-cache-'; const cacheNamePrefix = 'offline-cache-';
const cacheName = `${cacheNamePrefix}0.0.1`; const cacheName = `${cacheNamePrefix}0.0.1`;
const offlineAssetsInclude = [ /\.dll$/, /\.pdb$/, /\.wasm/, /\.html/, /\.js$/, /\.json$/, /\.css$/, /\.woff$/, /\.png$/, /\.jpe?g$/, /\.gif$/, /\.ico$/, /\.blat$/, /\.dat$/ ]; const offlineAssetsInclude = [ /\.dll$/, /\.pdb$/, /\.wasm/, /\.html/, /\.js$/, /\.json$/, /\.css$/, /\.woff$/, /\.png$/, /\.jpe?g$/, /\.gif$/, /\.ico$/, /\.blat$/, /\.dat$/ ];
const offlineAssetsExclude = [ /^service-worker\.js$/ ]; // The globe (4 MB of script and textures) is fetched when the feed first shows it, never precached.
const offlineAssetsExclude = [ /^service-worker\.js$/, /^vendor\/globe\// ];
async function onInstall(event) { async function onInstall(event) {
console.info('Service worker: Install'); console.info('Service worker: Install');
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Vasco Asturiano
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+62
View File
@@ -0,0 +1,62 @@
Licences of the libraries bundled in globe.gl.min.js (globe.gl's own is LICENSE-globe.gl; three-globe, kapsule and
accessor-fn carry the same MIT notice by the same author).
=== three.js r185 ===
The MIT License
Copyright © 2010-2026 three.js authors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
=== @tweenjs/tween.js ===
The MIT License
Copyright (c) 2010-2012 Tween.js authors.
Easing equations Copyright (c) 2001 Robert Penner http://robertpenner.com/easing/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
=== d3 modules (ISC) ===
Copyright 2010-2023 Mike Bostock
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted,
provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
+17
View File
@@ -0,0 +1,17 @@
# The globe's vendored files
Copied once from the npm registry (registry.npmjs.org) on 2026-10-04; the build and the app never fetch them from
anywhere else. To update, download the new tarballs from the registry, copy the same files, and replace the hashes.
| File | From | Licence | sha256 |
|---|---|---|---|
| `globe.gl.min.js` | `globe.gl` 2.46.2, `dist/globe.gl.min.js` (UMD, defines `window.Globe`) | MIT, `LICENSE-globe.gl` | `2c3e445c04d121215910a89688b96091c8a72071c122a4f830081a39b636c94c` |
| `earth-blue-marble.jpg` | `three-globe` 2.45.3, `example/img/earth-blue-marble.jpg`, 4096×2048 | NASA Visible Earth "Blue Marble", public domain | `228deba2e4b600146bdcb6cfa359b8ead6aacc2b1c13550a29cd82824cfa1c01` |
| `earth-night.jpg` | `three-globe` 2.45.3, `example/img/earth-night.jpg`, 4096×2048 | NASA Earth Observatory "Black Marble" (city lights), public domain | `355ab23dd1323315b393d7b91dd2d7ee223a1cbaaba2b48dc72ba90d371ced24` |
`globe.gl.min.js` bundles its dependencies: three.js r185 (MIT, © 2010–2026 three.js authors), three-globe (MIT, © 2019
Vasco Asturiano), @tweenjs/tween.js (MIT), kapsule and accessor-fn (MIT, © Vasco Asturiano), and d3 modules (ISC, ©
Mike Bostock). Their notices are in `LICENSES-bundled.txt`.
The service worker leaves this folder out of the offline precache (`service-worker.published.js`): the feed page
loads it the first time it shows the globe.
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 698 KiB

+20
View File
@@ -0,0 +1,20 @@
// Version 2.46.2 globe.gl - https://github.com/vasturiano/globe.gl
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).Globe=t()}(this,function(){"use strict";!function(e,t){void 0===t&&(t={});var n=t.insertAt;if("undefined"!=typeof document){var r=document.head||document.getElementsByTagName("head")[0],i=document.createElement("style");i.type="text/css","top"===n&&r.firstChild?r.insertBefore(i,r.firstChild):r.appendChild(i),i.styleSheet?i.styleSheet.cssText=e:i.appendChild(document.createTextNode(e))}}(".scene-container .clickable {\n cursor: pointer;\n}");const e="185",t=0,n=1,r=2,i=0,s=1,a=2,o=3,l=1,u=3,c=0,h=1,d=2,A=100,p=101,f=102,m=200,g=201,_=202,v=203,y=204,b=205,x=206,T=207,S=208,w=209,M=210,E=211,C=212,R=213,N=214,P=0,D=1,L=2,I=3,U=4,B=5,O=6,F=7,k=0,V=1,q=2,z=1,G=2,H=3,j=4,W=5,X=6,$=7,Q=301,Y=302,K=303,Z=304,J=306,ee=1e3,te=1001,ne=1002,re=1003,ie=1004,se=1005,ae=1006,oe=1007,le=1008,ue=1009,ce=1010,he=1011,de=1012,Ae=1013,pe=1014,fe=1015,me=1016,ge=1017,_e=1018,ve=1020,ye=35902,be=35899,xe=1021,Te=1022,Se=1023,we=1026,Me=1027,Ee=1028,Ce=1029,Re=1030,Ne=1031,Pe=1032,De=1033,Le=33776,Ie=33777,Ue=33778,Be=33779,Oe=35840,Fe=35841,ke=35842,Ve=35843,qe=36196,ze=37492,Ge=37496,He=37488,je=37489,We=37490,Xe=37491,$e=37808,Qe=37809,Ye=37810,Ke=37811,Ze=37812,Je=37813,et=37814,tt=37815,nt=37816,rt=37817,it=37818,st=37819,at=37820,ot=37821,lt=36492,ut=36494,ct=36495,ht=36283,dt=36284,At=36285,pt=36286,ft="",mt="srgb",gt="srgb-linear",_t="linear",vt="srgb",yt=7680,bt=512,xt=513,Tt=514,St=515,wt=516,Mt=517,Et=518,Ct=519,Rt=35044,Nt=35048,Pt="300 es",Dt=2e3,Lt=2001,It="compute",Ut="render",Bt="depthTextureCompare";function Ot(e){return ArrayBuffer.isView(e)&&!(e instanceof DataView)}function Ft(e){return document.createElementNS("http://www.w3.org/1999/xhtml",e)}function kt(){const e=Ft("canvas");return e.style.display="block",e}const Vt={};function qt(...e){const t="THREE."+e.shift();console.log(t,...e)}function zt(e){const t=e[0];if("string"==typeof t&&t.startsWith("TSL:")){const t=e[1];t&&t.isStackTrace?e[0]+=" "+t.getLocation():e[1]='Stack trace not available. Enable "THREE.Node.captureStackTrace" to capture stack traces.'}return e}function Gt(...e){const t="THREE."+(e=zt(e)).shift();{const n=e[0];n&&n.isStackTrace?console.warn(n.getError(t)):console.warn(t,...e)}}function Ht(...e){const t="THREE."+(e=zt(e)).shift();{const n=e[0];n&&n.isStackTrace?console.error(n.getError(t)):console.error(t,...e)}}function jt(...e){const t=e.join(" ");t in Vt||(Vt[t]=!0,Gt(...e))}function Wt(){return"undefined"!=typeof self&&void 0!==self.scheduler&&void 0!==self.scheduler.yield?self.scheduler.yield():new Promise(e=>{requestAnimationFrame(e)})}const Xt={[P]:1,[L]:6,[U]:7,[I]:5,[D]:0,[O]:2,[F]:4,[B]:3};class $t{addEventListener(e,t){void 0===this._listeners&&(this._listeners={});const n=this._listeners;void 0===n[e]&&(n[e]=[]),-1===n[e].indexOf(t)&&n[e].push(t)}hasEventListener(e,t){const n=this._listeners;return void 0!==n&&(void 0!==n[e]&&-1!==n[e].indexOf(t))}removeEventListener(e,t){const n=this._listeners;if(void 0===n)return;const r=n[e];if(void 0!==r){const e=r.indexOf(t);-1!==e&&r.splice(e,1)}}dispatchEvent(e){const t=this._listeners;if(void 0===t)return;const n=t[e.type];if(void 0!==n){e.target=this;const t=n.slice(0);for(let n=0,r=t.length;n<r;n++)t[n].call(this,e);e.target=null}}}const Qt=["00","01","02","03","04","05","06","07","08","09","0a","0b","0c","0d","0e","0f","10","11","12","13","14","15","16","17","18","19","1a","1b","1c","1d","1e","1f","20","21","22","23","24","25","26","27","28","29","2a","2b","2c","2d","2e","2f","30","31","32","33","34","35","36","37","38","39","3a","3b","3c","3d","3e","3f","40","41","42","43","44","45","46","47","48","49","4a","4b","4c","4d","4e","4f","50","51","52","53","54","55","56","57","58","59","5a","5b","5c","5d","5e","5f","60","61","62","63","64","65","66","67","68","69","6a","6b","6c","6d","6e","6f","70","71","72","73","74","75","76","77","78","79","7a","7b","7c","7d","7e","7f","80","81","82","83","84","85","86","87","88","89","8a","8b","8c","8d","8e","8f","90","91","92","93","94","95","96","97","98","99","9a","9b","9c","9d","9e","9f","a0","a1","a2","a3","a4","a5","a6","a7","a8","a9","aa","ab","ac","ad","ae","af","b0","b1","b2","b3","b4","b5","b6","b7","b8","b9","ba","bb","bc","bd","be","bf","c0","c1","c2","c3","c4","c5","c6","c7","c8","c9","ca","cb","cc","cd","ce","cf","d0","d1","d2","d3","d4","d5","d6","d7","d8","d9","da","db","dc","dd","de","df","e0","e1","e2","e3","e4","e5","e6","e7","e8","e9","ea","eb","ec","ed","ee","ef","f0","f1","f2","f3","f4","f5","f6","f7","f8","f9","fa","fb","fc","fd","fe","ff"];let Yt=1234567;const Kt=Math.PI/180,Zt=180/Math.PI;function Jt(){const e=4294967295*Math.random()|0,t=4294967295*Math.random()|0,n=4294967295*Math.random()|0,r=4294967295*Math.random()|0;return(Qt[255&e]+Qt[e>>8&255]+Qt[e>>16&255]+Qt[e>>24&255]+"-"+Qt[255&t]+Qt[t>>8&255]+"-"+Qt[t>>16&15|64]+Qt[t>>24&Line truncated
// <http://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef (WCAG Version 2)
// Analyze the 2 colors and returns the color contrast defined by (WCAG Version 2)
T_.readability=function(e,t){var n=T_(e),r=T_(t);return(Math.max(n.getLuminance(),r.getLuminance())+.05)/(Math.min(n.getLuminance(),r.getLuminance())+.05)},T_.isReadable=function(e,t,n){var r,i,s=T_.readability(e,t);switch(i=!1,(r=function(e){var t,n;t=((e=e||{level:"AA",size:"small"}).level||"AA").toUpperCase(),n=(e.size||"small").toLowerCase(),"AA"!==t&&"AAA"!==t&&(t="AA");"small"!==n&&"large"!==n&&(n="small");return{level:t,size:n}}(n)).level+r.size){case"AAsmall":case"AAAlarge":i=s>=4.5;break;case"AAlarge":i=s>=3;break;case"AAAsmall":i=s>=7}return i},T_.mostReadable=function(e,t,n){var r,i,s,a,o=null,l=0;i=(n=n||{}).includeFallbackColors,s=n.level,a=n.size;for(var u=0;u<t.length;u++)(r=T_.readability(e,t[u]))>l&&(l=r,o=T_(t[u]));return T_.isReadable(e,o,{level:s,size:a})||!i?o:(n.includeFallbackColors=!1,T_.mostReadable(e,["#fff","#000"],n))};var V_=T_.names={aliceblue:"f0f8ff",antiquewhite:"faebd7",aqua:"0ff",aquamarine:"7fffd4",azure:"f0ffff",beige:"f5f5dc",bisque:"ffe4c4",black:"000",blanchedalmond:"ffebcd",blue:"00f",blueviolet:"8a2be2",brown:"a52a2a",burlywood:"deb887",burntsienna:"ea7e5d",cadetblue:"5f9ea0",chartreuse:"7fff00",chocolate:"d2691e",coral:"ff7f50",cornflowerblue:"6495ed",cornsilk:"fff8dc",crimson:"dc143c",cyan:"0ff",darkblue:"00008b",darkcyan:"008b8b",darkgoldenrod:"b8860b",darkgray:"a9a9a9",darkgreen:"006400",darkgrey:"a9a9a9",darkkhaki:"bdb76b",darkmagenta:"8b008b",darkolivegreen:"556b2f",darkorange:"ff8c00",darkorchid:"9932cc",darkred:"8b0000",darksalmon:"e9967a",darkseagreen:"8fbc8f",darkslateblue:"483d8b",darkslategray:"2f4f4f",darkslategrey:"2f4f4f",darkturquoise:"00ced1",darkviolet:"9400d3",deeppink:"ff1493",deepskyblue:"00bfff",dimgray:"696969",dimgrey:"696969",dodgerblue:"1e90ff",firebrick:"b22222",floralwhite:"fffaf0",forestgreen:"228b22",fuchsia:"f0f",gainsboro:"dcdcdc",ghostwhite:"f8f8ff",gold:"ffd700",goldenrod:"daa520",gray:"808080",green:"008000",greenyellow:"adff2f",grey:"808080",honeydew:"f0fff0",hotpink:"ff69b4",indianred:"cd5c5c",indigo:"4b0082",ivory:"fffff0",khaki:"f0e68c",lavender:"e6e6fa",lavenderblush:"fff0f5",lawngreen:"7cfc00",lemonchiffon:"fffacd",lightblue:"add8e6",lightcoral:"f08080",lightcyan:"e0ffff",lightgoldenrodyellow:"fafad2",lightgray:"d3d3d3",lightgreen:"90ee90",lightgrey:"d3d3d3",lightpink:"ffb6c1",lightsalmon:"ffa07a",lightseagreen:"20b2aa",lightskyblue:"87cefa",lightslategray:"789",lightslategrey:"789",lightsteelblue:"b0c4de",lightyellow:"ffffe0",lime:"0f0",limegreen:"32cd32",linen:"faf0e6",magenta:"f0f",maroon:"800000",mediumaquamarine:"66cdaa",mediumblue:"0000cd",mediumorchid:"ba55d3",mediumpurple:"9370db",mediumseagreen:"3cb371",mediumslateblue:"7b68ee",mediumspringgreen:"00fa9a",mediumturquoise:"48d1cc",mediumvioletred:"c71585",midnightblue:"191970",mintcream:"f5fffa",mistyrose:"ffe4e1",moccasin:"ffe4b5",navajowhite:"ffdead",navy:"000080",oldlace:"fdf5e6",olive:"808000",olivedrab:"6b8e23",orange:"ffa500",orangered:"ff4500",orchid:"da70d6",palegoldenrod:"eee8aa",palegreen:"98fb98",paleturquoise:"afeeee",palevioletred:"db7093",papayawhip:"ffefd5",peachpuff:"ffdab9",peru:"cd853f",pink:"ffc0cb",plum:"dda0dd",powderblue:"b0e0e6",purple:"800080",rebeccapurple:"663399",red:"f00",rosybrown:"bc8f8f",royalblue:"4169e1",saddlebrown:"8b4513",salmon:"fa8072",sandybrown:"f4a460",seagreen:"2e8b57",seashell:"fff5ee",sienna:"a0522d",silver:"c0c0c0",skyblue:"87ceeb",slateblue:"6a5acd",slategray:"708090",slategrey:"708090",snow:"fffafa",springgreen:"00ff7f",steelblue:"4682b4",tan:"d2b48c",teal:"008080",thistle:"d8bfd8",tomato:"ff6347",turquoise:"40e0d0",violet:"ee82ee",wheat:"f5deb3",white:"fff",whitesmoke:"f5f5f5",yellow:"ff0",yellowgreen:"9acd32"},q_=T_.hexNames=function(e){var t={};for(var n in e)e.hasOwnProperty(n)&&(t[e[n]]=n);return t}(V_);function z_(e){return e=parseFloat(e),(isNaN(e)||e<0||e>1)&&(e=1),e}function G_(e,t){(function(e){return"string"==typeof e&&-1!=e.indexOf(".")&&1===parseFloat(e)})(e)&&(e="100%");var n=function(e){return"string"==typeof e&&-1!=e.indexOf("%")}(e);return e=Math.min(t,Math.max(0,parseFloat(e))),n&&(e=parseInt(e*t,10)/100),Math.abs(e-t)<1e-6?1:e%t/parseFloat(t)}function H_(e){return Math.min(1,Math.max(0,e))}function j_(e){return parseInt(e,16)}function W_(e){return 1==e.length?"0"+e:""+e}function X_(e){return e<=1&&(e=100*e+"%"),e}function $_(e){return Math.round(255*parseFloat(e)).toString(16)}function Q_(e){return j_(e)/255}var Y_,K_,Z_,J_=(K_="[\\s|\\(]+("+(Y_="(?:[-\\+]?\\d*\\.\\d+%?)|(?:[-\\+]?\\d+%?)")+")[,|\\s]+("+Y_+")[,|\\s]+("+Y_+")\\s*\\)?",Z_="[\\s|\\(]+("+Y_+")[,|\\s]+("+Y_+")[,|\\s]+("+Y_+")[,|\\s]+("+Y_+")\\s*\\)?",{CSS_UNIT:new RegExp(Y_),rgb:new RegExp("rgb"+K_),rgba:new RegExp("rgba"+Z_),hsl:new RegExp("hsl"+K_),hsla:new RegExp("hsla"+Z_),hsv:new RegExp("hsv"+K_),hsva:new RegExp("hsva"+Z_),hex3:/^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,hex6:/^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,hex4:/^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,hex8:/^#?([0-9a-fA-F]Line truncated
/*
* Copyright 2018-2019, 2022 Uber Technologies, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/var $y={};[["sizeOfH3Index",qy],["sizeOfLatLng",qy],["sizeOfCellBoundary",qy],["sizeOfGeoLoop",qy],["sizeOfGeoPolygon",qy],["sizeOfLinkedGeoPolygon",qy],["sizeOfCoordIJ",qy],["readInt64AsDoubleFromPointer",qy],["isValidCell",qy,[qy,qy]],["isValidIndex",qy,[qy,qy]],["latLngToCell",qy,[qy,qy,qy,qy]],["cellToLatLng",qy,[qy,qy,qy]],["cellToBoundary",qy,[qy,qy,qy]],["maxGridDiskSize",qy,[qy,qy]],["gridDisk",qy,[qy,qy,qy,qy]],["gridDiskDistances",qy,[qy,qy,qy,qy,qy]],["gridRing",qy,[qy,qy,qy,qy]],["gridRingUnsafe",qy,[qy,qy,qy,qy]],["maxPolygonToCellsSize",qy,[qy,qy,qy,qy]],["polygonToCells",qy,[qy,qy,qy,qy]],["maxPolygonToCellsSizeExperimental",qy,[qy,qy,qy,qy]],["polygonToCellsExperimental",qy,[qy,qy,qy,qy,qy,qy]],["cellsToLinkedMultiPolygon",qy,[qy,qy,qy]],["destroyLinkedMultiPolygon",null,[qy]],["compactCells",qy,[qy,qy,qy,qy]],["uncompactCells",qy,[qy,qy,qy,qy,qy,qy]],["uncompactCellsSize",qy,[qy,qy,qy,qy,qy]],["isPentagon",qy,[qy,qy]],["isResClassIII",qy,[qy,qy]],["getBaseCellNumber",qy,[qy,qy]],["getResolution",qy,[qy,qy]],["getIndexDigit",qy,[qy,qy,qy]],["constructCell",qy,[qy,qy,qy,qy]],["maxFaceCount",qy,[qy,qy,qy]],["getIcosahedronFaces",qy,[qy,qy,qy]],["cellToParent",qy,[qy,qy,qy,qy]],["cellToChildren",qy,[qy,qy,qy,qy]],["cellToCenterChild",qy,[qy,qy,qy,qy]],["cellToChildrenSize",qy,[qy,qy,qy,qy]],["cellToChildPos",qy,[qy,qy,qy,qy]],["childPosToCell",qy,[qy,qy,qy,qy,qy,qy]],["areNeighborCells",qy,[qy,qy,qy,qy,qy]],["cellsToDirectedEdge",qy,[qy,qy,qy,qy,qy]],["getDirectedEdgeOrigin",qy,[qy,qy,qy]],["getDirectedEdgeDestination",qy,[qy,qy,qy]],["isValidDirectedEdge",qy,[qy,qy]],["directedEdgeToCells",qy,[qy,qy,qy]],["originToDirectedEdges",qy,[qy,qy,qy]],["directedEdgeToBoundary",qy,[qy,qy,qy]],["reverseDirectedEdge",qy,[qy,qy,qy]],["gridDistance",qy,[qy,qy,qy,qy,qy]],["gridPathCells",qy,[qy,qy,qy,qy,qy]],["gridPathCellsSize",qy,[qy,qy,qy,qy,qy]],["cellToLocalIj",qy,[qy,qy,qy,qy,qy,qy]],["localIjToCell",qy,[qy,qy,qy,qy,qy]],["getHexagonAreaAvgM2",qy,[qy,qy]],["getHexagonAreaAvgKm2",qy,[qy,qy]],["getHexagonEdgeLengthAvgM",qy,[qy,qy]],["getHexagonEdgeLengthAvgKm",qy,[qy,qy]],["greatCircleDistanceM",qy,[qy,qy]],["greatCircleDistanceKm",qy,[qy,qy]],["greatCircleDistanceRads",qy,[qy,qy]],["cellAreaM2",qy,[qy,qy,qy]],["cellAreaKm2",qy,[qy,qy,qy]],["cellAreaRads2",qy,[qy,qy,qy]],["edgeLengthM",qy,[qy,qy,qy]],["edgeLengthKm",qy,[qy,qy,qy]],["edgeLengthRads",qy,[qy,qy,qy]],["getNumCells",qy,[qy,qy]],["getRes0Cells",qy,[qy]],["res0CellCount",qy],["getPentagons",qy,[qy,qy]],["pentagonCount",qy],["cellToVertex",qy,[qy,qy,qy,qy]],["cellToVertexes",qy,[qy,qy,qy]],["vertexToLatLng",qy,[qy,qy,qy]],["isValidVertex",qy,[qy,qy]]].forEach(function(e){$y[e[0]]=Vy.cwrap.apply(Vy,e)});var Qy=16,Yy=$y.sizeOfH3Index(),Ky=$y.sizeOfLatLng(),Zy=$y.sizeOfCellBoundary(),Jy=$y.sizeOfGeoPolygon(),eb=$y.sizeOfGeoLoop();$y.sizeOfLinkedGeoPolygon(),$y.sizeOfCoordIJ();var tb=Math.pow(2,32)-1;var nb=/[^0-9a-fA-F]/;function rb(e){if(Array.isArray(e)&&2===e.length&&Number.isInteger(e[0])&&Number.isInteger(e[1]))return e;if("string"!=typeof e||nb.test(e))return[0,0];var t=parseInt(e.substring(0,e.length-8),Qy);return[parseInt(e.substring(e.length-8),Qy),t]}function ib(e){if(e>=0)return e.toString(Qy);var t=sb(8,(e&=2147483647).toString(Qy));return t=(parseInt(t[0],Qy)+8).toString(Qy)+t.substring(1)}function sb(e,t){for(var n=e-t.length,r="",i=0;i<n;i++)r+="0";return r+=t}function ab(e,t,n){for(var r=e.length,i=Vy._calloc(r,Ky),s=n?1:0,a=n?0:1,o=0;o<2*r;o+=2)Vy.HEAPF64.set([e[o/2][s],e[o/2][a]].map(pb),i/8+o);return Vy.HEAPU32.set([r,i],t/4),t}function ob(e,t){void 0===t&&(t=0);var n=Vy.getValue(e+Yy*t,"i32"),r=Vy.getValue(e+Yy*t+4,"i32");return r?function(e,t){return ib(t)+sb(8,ib(e))}(n,r):null}function lb(e){return 180*Vy.getValue(e,"double")/Math.PI}function ub(e){return[lb(e+8),lb(e)]}function cb(e,t,n){var r=Vy._malloc(Ky);Vy.HEAPF64.set([e,t].map(pb),r/8);var i=Vy._malloc(Yy);try{return Xy($y.latLngToCell(r,n,i)),function(e){if(!e)throw Wy(1002);return e}(ob(i))}finally{Vy._free(i),Vy._free(r)}}function hb(e){var t,n=Vy._malloc(Ky),r=rb(e),i=r[0],s=r[1];try{return Xy($y.cellToLatLng(i,s,n)),[lb(t=n),lb(t+8)]}finally{Vy._free(n)}}function db(e,t){var n=Vy._malloc(Zy),r=rb(e),i=r[0],s=r[1];try{return Xy($y.cellToBoundary(i,s,n)),function(e){for(var t=Vy.getValue(e,"i32"),n=e+8,r=[],i=ub,s=0;s<2*t;s+=2)r.push(i(n+8*s));return r.push(r[0]),r}(n)}finally{Vy._free(n)}}function Ab(e,t,n){if(function(e){if("number"!=typeof e||e<0||e>15||Math.floor(e)!==e)throw jy(4,e)}(t),n=Boolean(n),0===e.length||0===e[0].length)return[];var r,i=function(e,t){var n,r=e.length-1,i=Vy._calloc(Jy),s=0+eb,a=s+4;if(ab(e[0],i+0,t),r>0){n=Vy._calloc(r,eb);for(var o=0;o<r;o++)ab(e[o+1],n+eb*o,t)}return Vy.setValue(i+s,r,"i32"),Vy.setValue(i+a,n,"i32"),i}("number"==typeof e[0][0]?[e]:e,n),s=Vy._malloc(8);try{Xy($y.maxPolygonToCellsSize(i,t,0,s));var a=function(e){if(e>tb)throw Wy(1001,e);return e}((r=s,$y.readInt64AsDoubleFromPointer(r))),o=Vy._calloc(a,Yy);try{rLine truncated