('/admin/login-locks/reset', body),
+ onSuccess: () => qc.invalidateQueries({ queryKey: loginLockKeys.all }),
+ });
+}
diff --git a/server/dashboard/src/modules/login-locks/index.ts b/server/dashboard/src/modules/login-locks/index.ts
new file mode 100644
index 0000000..2b4d405
--- /dev/null
+++ b/server/dashboard/src/modules/login-locks/index.ts
@@ -0,0 +1,13 @@
+import { ShieldAlert } from 'lucide-react';
+import type { Module } from '../types';
+import LoginLocksPage from './LoginLocksPage';
+
+export const LoginLocksModule: Module = {
+ id: 'login-locks',
+ label: 'Login security',
+ icon: ShieldAlert,
+ path: '/login-locks',
+ element: LoginLocksPage,
+ requiredRole: 'admin',
+ weight: 45,
+};
diff --git a/server/dashboard/src/modules/registry.ts b/server/dashboard/src/modules/registry.ts
index 90bce6e..52c1d85 100644
--- a/server/dashboard/src/modules/registry.ts
+++ b/server/dashboard/src/modules/registry.ts
@@ -2,6 +2,7 @@ import { ApiKeysModule } from './api-keys';
import { GithubIntegrationModule } from './github-integration';
import { GroupsModule } from './groups';
import { HomeModule } from './home';
+import { LoginLocksModule } from './login-locks';
import { ManagedTunnelsModule } from './managed-tunnels';
import { ProjectsModule } from './projects';
import { SearchModule } from './search';
@@ -28,6 +29,7 @@ export const MODULES: Module[] = [
GithubIntegrationModule,
ManagedTunnelsModule,
UsersModule,
+ LoginLocksModule,
GroupsModule,
SettingsModule,
ServerModule,
diff --git a/server/dashboard/src/modules/users/components/ResetPasswordDialog.tsx b/server/dashboard/src/modules/users/components/ResetPasswordDialog.tsx
new file mode 100644
index 0000000..425aace
--- /dev/null
+++ b/server/dashboard/src/modules/users/components/ResetPasswordDialog.tsx
@@ -0,0 +1,117 @@
+import { useState } from 'react';
+import { KeyRound, Loader2 } from 'lucide-react';
+import { toast } from 'sonner';
+import { ApiError } from '@/api/client';
+import { Alert, AlertDescription } from '@/ui/alert';
+import { Button } from '@/ui/button';
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+ DialogTrigger,
+} from '@/ui/dialog';
+import { Input } from '@/ui/input';
+import { Label } from '@/ui/label';
+import { useResetUserPassword } from '../hooks';
+
+// Admin-initiated reset. Mirrors the invite flow: the admin sets a temporary
+// password and shares it out-of-band. The server flags the user
+// must_change_password=true and revokes their sessions, so on next login they
+// are forced to pick a new password (same as first login). Field minimum
+// (≥8 chars) mirrors the server.
+export function ResetPasswordDialog({
+ userId,
+ email,
+}: {
+ userId: string;
+ email: string;
+}) {
+ const [open, setOpen] = useState(false);
+ const [pw, setPw] = useState('');
+ const reset = useResetUserPassword();
+
+ function clear() {
+ setPw('');
+ reset.reset();
+ }
+
+ async function onSubmit() {
+ if (pw.length < 8) return;
+ try {
+ await reset.mutateAsync({ id: userId, body: { new_password: pw } });
+ toast.success('Password reset', {
+ description: `Share the temporary password with ${email}. They will be required to change it on next login.`,
+ });
+ setOpen(false);
+ clear();
+ } catch (err) {
+ const detail = err instanceof ApiError ? err.detail : String(err);
+ toast.error('Failed to reset password', { description: detail });
+ }
+ }
+
+ return (
+ {
+ setOpen(next);
+ if (!next) clear();
+ }}
+ >
+
+
+
+ Reset password
+
+
+
+
+ Reset password
+
+ Sets a temporary password for {email}. They are forced to change it
+ on next login and any active sessions are signed out.
+
+
+
+
+
+
Temporary password
+
setPw(e.target.value)}
+ placeholder="At least 8 characters"
+ />
+
+ Shown once. Share via your team’s preferred secure channel.
+
+
+
+
+ The account will be flagged{' '}
+ must_change_password{' '}
+ and its sessions revoked; the user cannot continue until they pick
+ a new password.
+
+
+
+
+
+ setOpen(false)} disabled={reset.isPending}>
+ Cancel
+
+
+ {reset.isPending ? : null}
+ Reset password
+
+
+
+
+ );
+}
diff --git a/server/dashboard/src/modules/users/components/UsersTable.tsx b/server/dashboard/src/modules/users/components/UsersTable.tsx
index 733c1df..56f3d68 100644
--- a/server/dashboard/src/modules/users/components/UsersTable.tsx
+++ b/server/dashboard/src/modules/users/components/UsersTable.tsx
@@ -12,6 +12,7 @@ import { cn } from '@/lib/cn';
import { formatDateTime, formatRelative } from '@/lib/formatDate';
import { DeleteUserDialog } from './DeleteUserDialog';
import { DisableUserButton } from './DisableUserButton';
+import { ResetPasswordDialog } from './ResetPasswordDialog';
import { UserRoleSelect } from './UserRoleSelect';
import { UserLocalProjectToggle } from './UserLocalProjectToggle';
@@ -97,6 +98,7 @@ export function UsersTable({
{isSelf ? null : (
<>
+
>
diff --git a/server/dashboard/src/modules/users/hooks.ts b/server/dashboard/src/modules/users/hooks.ts
index d8baab6..fd3171d 100644
--- a/server/dashboard/src/modules/users/hooks.ts
+++ b/server/dashboard/src/modules/users/hooks.ts
@@ -2,6 +2,7 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { api } from '@/api/client';
import type {
CreateUserRequest,
+ ResetUserPasswordRequest,
UpdateUserRequest,
User,
UserListResponse,
@@ -35,6 +36,15 @@ export function useUpdateUser() {
});
}
+export function useResetUserPassword() {
+ const qc = useQueryClient();
+ return useMutation({
+ mutationFn: ({ id, body }: { id: string; body: ResetUserPasswordRequest }) =>
+ api.post(`/admin/users/${id}/reset-password`, body),
+ onSuccess: () => qc.invalidateQueries({ queryKey: userKeys.all }),
+ });
+}
+
export function useDeleteUser() {
const qc = useQueryClient();
return useMutation({
diff --git a/server/internal/chunker/chunker.go b/server/internal/chunker/chunker.go
index b5e34a2..f8768b0 100644
--- a/server/internal/chunker/chunker.go
+++ b/server/internal/chunker/chunker.go
@@ -432,6 +432,15 @@ func defaultRegistry() map[string]languageEntry {
},
identifiers: idID("type_identifier"),
},
+ "solidity": {
+ factory: grammars.SolidityLanguage,
+ nodes: map[string][]string{
+ "function": {"function_definition", "modifier_definition", "constructor_definition", "fallback_receive_definition"},
+ "class": {"contract_declaration", "library_declaration"},
+ "type": {"interface_declaration", "struct_declaration", "enum_declaration", "event_definition"},
+ },
+ identifiers: idID(),
+ },
}
}
diff --git a/server/internal/chunker/chunker_test.go b/server/internal/chunker/chunker_test.go
index 15310c5..78463f8 100644
--- a/server/internal/chunker/chunker_test.go
+++ b/server/internal/chunker/chunker_test.go
@@ -475,6 +475,124 @@ end
}
}
+func TestChunkFile_Solidity(t *testing.T) {
+ src := `// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+interface IERC20 {
+ function transfer(address to, uint256 amount) external returns (bool);
+}
+
+contract Token is IERC20 {
+ enum State { Active, Paused }
+
+ function transfer(address to, uint256 amount) external returns (bool) {
+ return true;
+ }
+}
+`
+ chunks, _, err := ChunkFile("Token.sol", src, "solidity", 0)
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if len(chunks) == 0 {
+ t.Fatal("expected chunks from Solidity source")
+ }
+ counts := chunkTypeCounts(chunks)
+ if counts["class"] == 0 {
+ t.Errorf("expected a class chunk for the contract, got: %v", counts)
+ }
+
+ var names []string
+ for _, c := range chunks {
+ if c.SymbolName != nil {
+ names = append(names, *c.SymbolName)
+ }
+ }
+ if len(names) == 0 {
+ t.Fatalf("expected named symbols from Solidity source, got none (chunk types: %v)", counts)
+ }
+ want := map[string]bool{"Token": false, "transfer": false}
+ for _, n := range names {
+ if _, ok := want[n]; ok {
+ want[n] = true
+ }
+ }
+ for sym, found := range want {
+ if !found {
+ t.Errorf("expected symbol %q among extracted symbols %v", sym, names)
+ }
+ }
+}
+
+// TestRegistry_SolidityAllNodeKindsPresent is a stricter sibling to
+// TestRegistry_NodeNamesMatchAST: the generic test passes if *any* one of a
+// language's configured node types appears in the AST, which would let a
+// grammar rename of e.g. `modifier_definition` slip through unnoticed.
+//
+// Solidity's registry entry advertises 10 node kinds. This test parses a
+// contract that exercises every one of them and fails loudly if any single
+// kind is missing from the AST — protecting downstream `cix def` / `cix refs`
+// behavior for modifiers, events, constructors, and receive/fallback
+// functions, which are easy to overlook in the broader smoke test.
+func TestRegistry_SolidityAllNodeKindsPresent(t *testing.T) {
+ defer Configure(nil)
+ Configure(nil)
+
+ src := `// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+interface I { function f() external; }
+library L { function g() internal pure returns (uint) { return 1; } }
+contract C {
+ struct S { uint x; }
+ enum E { A, B }
+ event Ev(uint x);
+ modifier m() { _; }
+ constructor() {}
+ receive() external payable {}
+ function f() public {}
+}
+`
+
+ registryMu.RLock()
+ fn, ok := languageRegistry["solidity"]
+ nodes := languageNodes["solidity"]
+ registryMu.RUnlock()
+ if !ok {
+ t.Fatal("solidity not in registry")
+ }
+ if nodes == nil {
+ t.Fatal("solidity has no node map")
+ }
+
+ grammar := fn()
+ if grammar == nil {
+ t.Fatal("nil solidity grammar")
+ }
+
+ parser := sitter.NewParser(grammar)
+ tree, err := parser.Parse([]byte(src))
+ if err != nil {
+ t.Fatalf("parse error: %v", err)
+ }
+ root := tree.RootNode()
+ if root == nil {
+ t.Fatal("nil root")
+ }
+
+ seen := map[string]struct{}{}
+ collectNodeTypes(root, grammar, seen)
+
+ for _, types := range nodes {
+ for _, ty := range types {
+ if _, found := seen[ty]; !found {
+ t.Errorf("configured Solidity node type %q not present in AST — grammar rename?", ty)
+ }
+ }
+ }
+}
+
// --- Configure() filtering ---
func TestConfigure_FilterToSubset(t *testing.T) {
@@ -605,6 +723,22 @@ func TestRegistry_NodeNamesMatchAST(t *testing.T) {
"fortran": "subroutine s\nend subroutine\n",
"haskell": "module M where\n\nf :: Int -> Int\nf x = x\n",
"ocaml": "let f x = x\n",
+ // Covers every configured kind: contract_declaration, library_declaration,
+ // interface_declaration, struct_declaration, enum_declaration, event_definition,
+ // function_definition, modifier_definition, constructor_definition,
+ // fallback_receive_definition. Guards against grammar renames for any of them.
+ "solidity": "" +
+ "interface I { function f() external; }\n" +
+ "library L { function g() internal pure returns (uint) { return 1; } }\n" +
+ "contract C {\n" +
+ " struct S { uint x; }\n" +
+ " enum E { A, B }\n" +
+ " event Ev(uint x);\n" +
+ " modifier m() { _; }\n" +
+ " constructor() {}\n" +
+ " receive() external payable {}\n" +
+ " function f() public {}\n" +
+ "}\n",
}
for lang, src := range fixtures {
diff --git a/server/internal/httpapi/admin_embeddings.go b/server/internal/httpapi/admin_embeddings.go
index c4529e0..5ed2b1c 100644
--- a/server/internal/httpapi/admin_embeddings.go
+++ b/server/internal/httpapi/admin_embeddings.go
@@ -22,7 +22,7 @@ import (
"github.com/dvcdsys/code-index/server/internal/embeddings"
"github.com/dvcdsys/code-index/server/internal/embeddings/provider"
"github.com/dvcdsys/code-index/server/internal/embeddingscfg"
- "github.com/go-chi/chi/v5"
+ "github.com/dvcdsys/code-index/server/internal/httpapi/openapi"
)
// providerInfoPayload is the per-kind entry in GET /embedding-providers.
@@ -249,11 +249,11 @@ func (s *Server) SwitchEmbeddingProvider(w http.ResponseWriter, r *http.Request)
// persisting it), Starts it, then Stops it. Returns the detected
// dimension and a success flag, or a typed error message the
// dashboard can render verbatim.
-func (s *Server) TestEmbeddingProvider(w http.ResponseWriter, r *http.Request) {
+func (s *Server) TestEmbeddingProvider(w http.ResponseWriter, r *http.Request, kindParam openapi.TestEmbeddingProviderParamsKind) {
if _, ok := s.mustBeAdmin(w, r); !ok {
return
}
- kind := chi.URLParam(r, "kind")
+ kind := string(kindParam)
if kind == "" {
writeError(w, http.StatusBadRequest, "kind is required")
return
diff --git a/server/internal/httpapi/auth.go b/server/internal/httpapi/auth.go
index eec77eb..0650cad 100644
--- a/server/internal/httpapi/auth.go
+++ b/server/internal/httpapi/auth.go
@@ -473,6 +473,46 @@ func (s *Server) DeleteUser(w http.ResponseWriter, r *http.Request, id string) {
w.WriteHeader(http.StatusNoContent)
}
+// ResetUserPassword — POST /api/v1/admin/users/{id}/reset-password (admin only).
+//
+// Sets a new admin-chosen temporary password and forces the user to change it
+// on next login (must_change_password=1), mirroring the invite flow. Any admin
+// may reset any user, including another admin — a reset neither demotes nor
+// disables anyone, so no last-admin guard applies. The target user's existing
+// sessions are revoked so they must log back in and pass the change-password
+// gate.
+func (s *Server) ResetUserPassword(w http.ResponseWriter, r *http.Request, id string) {
+ if _, ok := s.mustBeAdmin(w, r); !ok {
+ return
+ }
+ var body struct {
+ NewPassword string `json:"new_password"`
+ }
+ if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
+ writeError(w, http.StatusUnprocessableEntity, "invalid JSON body")
+ return
+ }
+ if len(body.NewPassword) < users.MinPasswordLength {
+ writeError(w, http.StatusUnprocessableEntity, "new_password must be at least 8 characters")
+ return
+ }
+ if err := s.Deps.Users.AdminResetPassword(r.Context(), id, body.NewPassword); err != nil {
+ respondUserMutationError(w, err)
+ return
+ }
+ // Force re-login: best-effort revoke of all the target user's sessions.
+ // Failure here is non-fatal — the new password and flag are already set.
+ if s.Deps.Sessions != nil {
+ _ = s.Deps.Sessions.DeleteAllForUser(r.Context(), id)
+ }
+ u, err := s.Deps.Users.GetByID(r.Context(), id)
+ if err != nil {
+ respondUserMutationError(w, err)
+ return
+ }
+ writeJSON(w, http.StatusOK, userToPayload(u))
+}
+
func respondUserMutationError(w http.ResponseWriter, err error) {
switch {
case errors.Is(err, users.ErrNotFound):
diff --git a/server/internal/httpapi/auth_test.go b/server/internal/httpapi/auth_test.go
index 0e65431..b80537c 100644
--- a/server/internal/httpapi/auth_test.go
+++ b/server/internal/httpapi/auth_test.go
@@ -318,6 +318,123 @@ func TestCreateUser_AdminOnly(t *testing.T) {
}
}
+// resetPasswordRR POSTs to the admin reset-password endpoint as the caller
+// holding `cookie` and returns the recorder.
+func resetPasswordRR(t *testing.T, router http.Handler, cookie, userID, newPassword string) *httptest.ResponseRecorder {
+ t.Helper()
+ body, _ := json.Marshal(map[string]string{"new_password": newPassword})
+ req := withCookie(httptest.NewRequest(http.MethodPost, "/api/v1/admin/users/"+userID+"/reset-password", bytes.NewReader(body)), cookie)
+ req.Header.Set("Content-Type", "application/json")
+ rr := httptest.NewRecorder()
+ router.ServeHTTP(rr, req)
+ return rr
+}
+
+func TestResetUserPassword_AdminFlow(t *testing.T) {
+ f := newAuthFixture(t)
+ adminCookie := sessionCookie(loginRR(t, f.Router, "admin@example.com", "secret-password"))
+
+ // Seed a target user who is NOT flagged to change their password (so we
+ // can prove the reset sets the flag).
+ target, err := f.Deps.Users.Create(context.Background(), "target@example.com", "oldpassword1", users.RoleUser, false)
+ if err != nil {
+ t.Fatalf("seed target: %v", err)
+ }
+ // The target logs in once — gives us a live session to prove revocation.
+ targetCookie := sessionCookie(loginRR(t, f.Router, "target@example.com", "oldpassword1"))
+ if targetCookie == "" {
+ t.Fatalf("target login did not set a cookie")
+ }
+
+ // Admin resets the target's password.
+ rr := resetPasswordRR(t, f.Router, adminCookie, target.ID, "freshpass123")
+ if rr.Code != http.StatusOK {
+ t.Fatalf("admin reset status = %d (body=%s)", rr.Code, rr.Body.String())
+ }
+ var payload struct {
+ MustChangePassword bool `json:"must_change_password"`
+ }
+ _ = json.Unmarshal(rr.Body.Bytes(), &payload)
+ if !payload.MustChangePassword {
+ t.Errorf("response must_change_password = false, want true")
+ }
+
+ // The old password no longer works; the new temp password does.
+ if rr := loginRR(t, f.Router, "target@example.com", "oldpassword1"); rr.Code == http.StatusOK {
+ t.Errorf("login with OLD password succeeded, want failure")
+ }
+ relogin := loginRR(t, f.Router, "target@example.com", "freshpass123")
+ if relogin.Code != http.StatusOK {
+ t.Fatalf("login with NEW password status = %d (body=%s)", relogin.Code, relogin.Body.String())
+ }
+ var loginBody struct {
+ User struct {
+ MustChangePassword bool `json:"must_change_password"`
+ } `json:"user"`
+ }
+ _ = json.Unmarshal(relogin.Body.Bytes(), &loginBody)
+ if !loginBody.User.MustChangePassword {
+ t.Errorf("login payload must_change_password = false, want true")
+ }
+
+ // The target's PRE-EXISTING session was revoked.
+ req := withCookie(httptest.NewRequest(http.MethodGet, "/api/v1/auth/me", nil), targetCookie)
+ meRR := httptest.NewRecorder()
+ f.Router.ServeHTTP(meRR, req)
+ if meRR.Code != http.StatusUnauthorized {
+ t.Errorf("pre-reset session /auth/me status = %d, want 401", meRR.Code)
+ }
+}
+
+func TestResetUserPassword_AdminOnly(t *testing.T) {
+ f := newAuthFixture(t)
+
+ // Seed a non-admin who will both be the target and attempt the reset.
+ viewer, err := f.Deps.Users.Create(context.Background(), "viewer@example.com", "viewerpass1", users.RoleUser, false)
+ if err != nil {
+ t.Fatalf("seed viewer: %v", err)
+ }
+ viewerCookie := sessionCookie(loginRR(t, f.Router, "viewer@example.com", "viewerpass1"))
+
+ rr := resetPasswordRR(t, f.Router, viewerCookie, viewer.ID, "newpass12345")
+ if rr.Code != http.StatusForbidden {
+ t.Errorf("viewer reset status = %d, want 403", rr.Code)
+ }
+}
+
+func TestResetUserPassword_CanResetAnotherAdmin(t *testing.T) {
+ f := newAuthFixture(t)
+ adminCookie := sessionCookie(loginRR(t, f.Router, "admin@example.com", "secret-password"))
+
+ other, err := f.Deps.Users.Create(context.Background(), "other-admin@example.com", "otheradmin1", users.RoleAdmin, false)
+ if err != nil {
+ t.Fatalf("seed other admin: %v", err)
+ }
+ rr := resetPasswordRR(t, f.Router, adminCookie, other.ID, "resetadmin123")
+ if rr.Code != http.StatusOK {
+ t.Errorf("reset another admin status = %d (body=%s), want 200", rr.Code, rr.Body.String())
+ }
+}
+
+func TestResetUserPassword_Validation(t *testing.T) {
+ f := newAuthFixture(t)
+ adminCookie := sessionCookie(loginRR(t, f.Router, "admin@example.com", "secret-password"))
+
+ // Unknown user id → 404.
+ if rr := resetPasswordRR(t, f.Router, adminCookie, "does-not-exist", "validpass123"); rr.Code != http.StatusNotFound {
+ t.Errorf("unknown id status = %d, want 404 (body=%s)", rr.Code, rr.Body.String())
+ }
+
+ // Seed a real target, then send a too-short password → 422.
+ target, err := f.Deps.Users.Create(context.Background(), "shortpw@example.com", "oldpassword1", users.RoleUser, false)
+ if err != nil {
+ t.Fatalf("seed target: %v", err)
+ }
+ if rr := resetPasswordRR(t, f.Router, adminCookie, target.ID, "short"); rr.Code != http.StatusUnprocessableEntity {
+ t.Errorf("short password status = %d, want 422 (body=%s)", rr.Code, rr.Body.String())
+ }
+}
+
// --- API key CRUD via HTTP ---
func TestApiKey_CreateListRevokeFlow(t *testing.T) {
diff --git a/server/internal/httpapi/loginlimiter.go b/server/internal/httpapi/loginlimiter.go
index 5c72b32..0cee046 100644
--- a/server/internal/httpapi/loginlimiter.go
+++ b/server/internal/httpapi/loginlimiter.go
@@ -91,6 +91,86 @@ func (l *loginLimiter) reset(ip, email string) {
delete(l.perKey, loginLimiterKey(ip, email))
}
+// lockEntry describes one counter that is currently at or over its limit —
+// i.e. a login attempt matching it right now would be rejected with 429.
+type lockEntry struct {
+ Type string // "ip" or "ip_email"
+ IP string // source IP
+ Email string // lower-cased email; empty for a per-IP lock
+ Attempts int // attempts currently inside the window
+ Limit int // the window's cap
+ ExpiresAt time.Time // when the oldest attempt ages out and a slot frees
+}
+
+// locks returns every counter that is currently blocking new attempts. It
+// prunes expired timestamps as it walks (and drops emptied entries) so the
+// maps do not grow without bound between logins — the same prune-on-touch
+// discipline allow() applies. Callers get a point-in-time snapshot; the
+// windows keep sliding, so an entry may self-heal a moment later.
+func (l *loginLimiter) locks() []lockEntry {
+ l.mu.Lock()
+ defer l.mu.Unlock()
+ now := l.now()
+ out := []lockEntry{}
+
+ for ip, ts := range l.perIP {
+ pruned := pruneOlder(ts, now.Add(-l.ipWindow))
+ if len(pruned) == 0 {
+ delete(l.perIP, ip)
+ continue
+ }
+ l.perIP[ip] = pruned
+ if len(pruned) >= l.ipLimit {
+ out = append(out, lockEntry{
+ Type: "ip",
+ IP: ip,
+ Attempts: len(pruned),
+ Limit: l.ipLimit,
+ ExpiresAt: pruned[0].Add(l.ipWindow),
+ })
+ }
+ }
+
+ for key, ts := range l.perKey {
+ pruned := pruneOlder(ts, now.Add(-l.keyWindow))
+ if len(pruned) == 0 {
+ delete(l.perKey, key)
+ continue
+ }
+ l.perKey[key] = pruned
+ if len(pruned) >= l.keyLimit {
+ // Key is "ip|lower(email)"; IPv6 contains ':' but never '|',
+ // so a split on the first '|' recovers both halves cleanly.
+ ip, email, _ := strings.Cut(key, "|")
+ out = append(out, lockEntry{
+ Type: "ip_email",
+ IP: ip,
+ Email: email,
+ Attempts: len(pruned),
+ Limit: l.keyLimit,
+ ExpiresAt: pruned[0].Add(l.keyWindow),
+ })
+ }
+ }
+ return out
+}
+
+// clearIP drops the per-IP counter, immediately lifting a per-IP lock. Used
+// by the admin unlock endpoint; the normal post-login path never clears it.
+func (l *loginLimiter) clearIP(ip string) {
+ l.mu.Lock()
+ defer l.mu.Unlock()
+ delete(l.perIP, ip)
+}
+
+// clearKey drops the per-(IP, email) counter for the admin unlock path, which
+// targets a specific row surfaced by locks() rather than reacting to a login
+// success. It delegates to reset so the key-derivation logic lives in exactly
+// one place — the only difference is the calling context, not the behaviour.
+func (l *loginLimiter) clearKey(ip, email string) {
+ l.reset(ip, email)
+}
+
func checkSlidingWindow(ts []time.Time, now time.Time, window time.Duration, limit int) ([]time.Time, time.Duration, bool) {
pruned := pruneOlder(ts, now.Add(-window))
if len(pruned) >= limit {
diff --git a/server/internal/httpapi/loginlocks_admin.go b/server/internal/httpapi/loginlocks_admin.go
new file mode 100644
index 0000000..c7f3e7a
--- /dev/null
+++ b/server/internal/httpapi/loginlocks_admin.go
@@ -0,0 +1,118 @@
+package httpapi
+
+import (
+ "encoding/json"
+ "net/http"
+ "strings"
+ "time"
+)
+
+// Admin visibility + control over the in-memory login rate limiter
+// (loginlimiter.go). The limiter blocks brute-force login attempts per IP and
+// per (IP, email); both counters self-heal as their sliding windows expire,
+// but a legitimate user who fat-fingered their password from a shared office
+// IP can be stuck for the full 15-minute window. These endpoints let an admin
+// see who is currently locked and lift a specific lock early.
+//
+// State is per-process and wiped on restart, so this is an operational
+// convenience, not a persisted store — there is nothing to reconcile across
+// replicas (the server runs single-instance) and no audit trail beyond the
+// structured request log.
+
+type loginLockPayload struct {
+ Type string `json:"type"` // "ip" or "ip_email"
+ IP string `json:"ip"` // source IP
+ Email string `json:"email,omitempty"` // present only for type "ip_email"
+ Attempts int `json:"attempts"` // attempts inside the window right now
+ Limit int `json:"limit"` // the cap that tripped the lock
+ ExpiresAt string `json:"expires_at"` // RFC3339 — when a slot next frees
+}
+
+// ListLoginLocks — GET /api/v1/admin/login-locks (admin only).
+//
+// Returns every limiter counter currently at or over its threshold, i.e. the
+// IPs and (IP, email) pairs a login would be rejected for right now with 429.
+func (s *Server) ListLoginLocks(w http.ResponseWriter, r *http.Request) {
+ if _, ok := s.mustBeAdmin(w, r); !ok {
+ return
+ }
+ locks := []loginLockPayload{}
+ if s.loginLimiter != nil {
+ for _, e := range s.loginLimiter.locks() {
+ locks = append(locks, loginLockPayload{
+ Type: e.Type,
+ IP: e.IP,
+ Email: e.Email,
+ Attempts: e.Attempts,
+ Limit: e.Limit,
+ ExpiresAt: e.ExpiresAt.UTC().Format(time.RFC3339),
+ })
+ }
+ }
+ writeJSON(w, http.StatusOK, map[string]any{
+ "locks": locks,
+ "total": len(locks),
+ })
+}
+
+// ResetLoginLock — POST /api/v1/admin/login-locks/reset (admin only).
+//
+// Clears one counter surfaced by ListLoginLocks. `type` selects the map:
+// "ip" clears the per-IP horizontal-sweep counter; "ip_email" clears the
+// per-(IP, email) counter for a single account. The admin picks the exact row
+// to clear from the list, so we never guess across keys (clearing every IP
+// for an email would need a map scan and could lift more than intended).
+// Idempotent — clearing a key that is no longer locked is a no-op 204.
+func (s *Server) ResetLoginLock(w http.ResponseWriter, r *http.Request) {
+ ac, ok := s.mustBeAdmin(w, r)
+ if !ok {
+ return
+ }
+ var body struct {
+ Type string `json:"type"`
+ IP string `json:"ip"`
+ Email string `json:"email"`
+ }
+ if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
+ writeError(w, http.StatusUnprocessableEntity, "invalid JSON body")
+ return
+ }
+ body.IP = strings.TrimSpace(body.IP)
+ if body.IP == "" {
+ writeError(w, http.StatusUnprocessableEntity, "ip is required")
+ return
+ }
+ if s.loginLimiter == nil {
+ w.WriteHeader(http.StatusNoContent)
+ return
+ }
+ switch body.Type {
+ case "ip":
+ s.loginLimiter.clearIP(body.IP)
+ case "ip_email":
+ if strings.TrimSpace(body.Email) == "" {
+ writeError(w, http.StatusUnprocessableEntity, "email is required for type ip_email")
+ return
+ }
+ s.loginLimiter.clearKey(body.IP, body.Email)
+ default:
+ writeError(w, http.StatusUnprocessableEntity, `type must be "ip" or "ip_email"`)
+ return
+ }
+ // Clearing a lock weakens the brute-force defence, so record who did it
+ // to what, in an explicit audit line — not only the generic request log.
+ if s.Deps.Logger != nil {
+ actorID, actorEmail := "", ""
+ if ac != nil {
+ actorID, actorEmail = ac.User.ID, ac.User.Email
+ }
+ s.Deps.Logger.Info("admin cleared login rate-limit lock",
+ "actor_id", actorID,
+ "actor_email", actorEmail,
+ "lock_type", body.Type,
+ "lock_ip", body.IP,
+ "lock_email", body.Email,
+ )
+ }
+ w.WriteHeader(http.StatusNoContent)
+}
diff --git a/server/internal/httpapi/loginlocks_admin_test.go b/server/internal/httpapi/loginlocks_admin_test.go
new file mode 100644
index 0000000..495962b
--- /dev/null
+++ b/server/internal/httpapi/loginlocks_admin_test.go
@@ -0,0 +1,141 @@
+package httpapi
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "net/http"
+ "net/http/httptest"
+ "testing"
+
+ "github.com/dvcdsys/code-index/server/internal/users"
+)
+
+// loginLocksRR issues GET /api/v1/admin/login-locks as the given session.
+func loginLocksRR(t *testing.T, router http.Handler, cookie string) *httptest.ResponseRecorder {
+ t.Helper()
+ req := withCookie(httptest.NewRequest(http.MethodGet, "/api/v1/admin/login-locks", nil), cookie)
+ rr := httptest.NewRecorder()
+ router.ServeHTTP(rr, req)
+ return rr
+}
+
+// resetLoginLockRR issues POST /api/v1/admin/login-locks/reset with body.
+func resetLoginLockRR(t *testing.T, router http.Handler, cookie string, body map[string]string) *httptest.ResponseRecorder {
+ t.Helper()
+ raw, _ := json.Marshal(body)
+ req := withCookie(httptest.NewRequest(http.MethodPost, "/api/v1/admin/login-locks/reset", bytes.NewReader(raw)), cookie)
+ req.Header.Set("Content-Type", "application/json")
+ rr := httptest.NewRecorder()
+ router.ServeHTTP(rr, req)
+ return rr
+}
+
+type loginLockListBody struct {
+ Locks []struct {
+ Type string `json:"type"`
+ IP string `json:"ip"`
+ Email string `json:"email"`
+ Attempts int `json:"attempts"`
+ Limit int `json:"limit"`
+ } `json:"locks"`
+ Total int `json:"total"`
+}
+
+func TestLoginLocks_AdminOnly(t *testing.T) {
+ f := newAuthFixture(t)
+
+ if _, err := f.Deps.Users.Create(context.Background(), "viewer@example.com", "viewerpass1", users.RoleUser, false); err != nil {
+ t.Fatalf("seed viewer: %v", err)
+ }
+ viewerCookie := sessionCookie(loginRR(t, f.Router, "viewer@example.com", "viewerpass1"))
+
+ if rr := loginLocksRR(t, f.Router, viewerCookie); rr.Code != http.StatusForbidden {
+ t.Errorf("viewer GET login-locks status = %d, want 403", rr.Code)
+ }
+ rr := resetLoginLockRR(t, f.Router, viewerCookie, map[string]string{"type": "ip", "ip": "1.2.3.4"})
+ if rr.Code != http.StatusForbidden {
+ t.Errorf("viewer reset status = %d, want 403", rr.Code)
+ }
+}
+
+func TestLoginLocks_ListAndReset(t *testing.T) {
+ f := newAuthFixture(t)
+ adminCookie := sessionCookie(loginRR(t, f.Router, "admin@example.com", "secret-password"))
+
+ // Drive the per-(IP, email) counter to its limit with bad passwords. The
+ // default httptest RemoteAddr is 192.0.2.1, so every attempt shares one IP.
+ for range 5 {
+ if rr := loginRR(t, f.Router, "admin@example.com", "WRONG"); rr.Code != http.StatusUnauthorized {
+ t.Fatalf("warmup attempt status = %d, want 401", rr.Code)
+ }
+ }
+ // The lock is now active: a 6th attempt (even with the right password) 429s.
+ if rr := loginRR(t, f.Router, "admin@example.com", "secret-password"); rr.Code != http.StatusTooManyRequests {
+ t.Fatalf("post-limit status = %d, want 429", rr.Code)
+ }
+
+ // The admin can see exactly one ip_email lock for that IP/email.
+ listRR := loginLocksRR(t, f.Router, adminCookie)
+ if listRR.Code != http.StatusOK {
+ t.Fatalf("list status = %d (body=%s)", listRR.Code, listRR.Body.String())
+ }
+ var list loginLockListBody
+ if err := json.Unmarshal(listRR.Body.Bytes(), &list); err != nil {
+ t.Fatalf("decode list: %v", err)
+ }
+ if list.Total != 1 || len(list.Locks) != 1 {
+ t.Fatalf("total = %d, locks = %d, want 1/1 (body=%s)", list.Total, len(list.Locks), listRR.Body.String())
+ }
+ lock := list.Locks[0]
+ if lock.Type != "ip_email" || lock.IP != "192.0.2.1" || lock.Email != "admin@example.com" {
+ t.Errorf("lock = %+v, want type ip_email ip 192.0.2.1 email admin@example.com", lock)
+ }
+ if lock.Attempts < lock.Limit {
+ t.Errorf("attempts %d < limit %d — should be at or over limit", lock.Attempts, lock.Limit)
+ }
+
+ // Admin clears that exact row.
+ if rr := resetLoginLockRR(t, f.Router, adminCookie, map[string]string{
+ "type": "ip_email", "ip": "192.0.2.1", "email": "admin@example.com",
+ }); rr.Code != http.StatusNoContent {
+ t.Fatalf("reset status = %d (body=%s), want 204", rr.Code, rr.Body.String())
+ }
+
+ // The lock is gone from the list and login is no longer throttled (a wrong
+ // password now reaches the authenticator and returns 401, not 429).
+ if rr := loginLocksRR(t, f.Router, adminCookie); rr.Code == http.StatusOK {
+ var after loginLockListBody
+ _ = json.Unmarshal(rr.Body.Bytes(), &after)
+ if after.Total != 0 {
+ t.Errorf("post-reset total = %d, want 0", after.Total)
+ }
+ }
+ if rr := loginRR(t, f.Router, "admin@example.com", "WRONG"); rr.Code != http.StatusUnauthorized {
+ t.Errorf("post-reset login status = %d, want 401 (limiter cleared)", rr.Code)
+ }
+}
+
+func TestLoginLocks_ResetValidation(t *testing.T) {
+ f := newAuthFixture(t)
+ adminCookie := sessionCookie(loginRR(t, f.Router, "admin@example.com", "secret-password"))
+
+ cases := []struct {
+ name string
+ body map[string]string
+ want int
+ }{
+ {"missing ip", map[string]string{"type": "ip"}, http.StatusUnprocessableEntity},
+ {"bad type", map[string]string{"type": "nonsense", "ip": "1.2.3.4"}, http.StatusUnprocessableEntity},
+ {"ip_email without email", map[string]string{"type": "ip_email", "ip": "1.2.3.4"}, http.StatusUnprocessableEntity},
+ {"ip ok (idempotent no-op)", map[string]string{"type": "ip", "ip": "9.9.9.9"}, http.StatusNoContent},
+ }
+ for _, tc := range cases {
+ t.Run(tc.name, func(t *testing.T) {
+ rr := resetLoginLockRR(t, f.Router, adminCookie, tc.body)
+ if rr.Code != tc.want {
+ t.Errorf("status = %d, want %d (body=%s)", rr.Code, tc.want, rr.Body.String())
+ }
+ })
+ }
+}
diff --git a/server/internal/httpapi/openapi/openapi.gen.go b/server/internal/httpapi/openapi/openapi.gen.go
index 25551c2..875ce96 100644
--- a/server/internal/httpapi/openapi/openapi.gen.go
+++ b/server/internal/httpapi/openapi/openapi.gen.go
@@ -26,6 +26,27 @@ const (
BearerAuthScopes bearerAuthContextKey = "bearerAuth.Scopes"
)
+// Defines values for ActiveEmbeddingProviderKind.
+const (
+ ActiveEmbeddingProviderKindOllama ActiveEmbeddingProviderKind = "ollama"
+ ActiveEmbeddingProviderKindOpenai ActiveEmbeddingProviderKind = "openai"
+ ActiveEmbeddingProviderKindVoyage ActiveEmbeddingProviderKind = "voyage"
+)
+
+// Valid indicates whether the value is a known member of the ActiveEmbeddingProviderKind enum.
+func (e ActiveEmbeddingProviderKind) Valid() bool {
+ switch e {
+ case ActiveEmbeddingProviderKindOllama:
+ return true
+ case ActiveEmbeddingProviderKindOpenai:
+ return true
+ case ActiveEmbeddingProviderKindVoyage:
+ return true
+ default:
+ return false
+ }
+}
+
// Defines values for AddGitRepoRequestWebhookMode.
const (
AddGitRepoRequestWebhookModeAuto AddGitRepoRequestWebhookMode = "auto"
@@ -65,6 +86,27 @@ func (e CreateUserRequestRole) Valid() bool {
}
}
+// Defines values for EmbeddingProviderInfoKind.
+const (
+ EmbeddingProviderInfoKindOllama EmbeddingProviderInfoKind = "ollama"
+ EmbeddingProviderInfoKindOpenai EmbeddingProviderInfoKind = "openai"
+ EmbeddingProviderInfoKindVoyage EmbeddingProviderInfoKind = "voyage"
+)
+
+// Valid indicates whether the value is a known member of the EmbeddingProviderInfoKind enum.
+func (e EmbeddingProviderInfoKind) Valid() bool {
+ switch e {
+ case EmbeddingProviderInfoKindOllama:
+ return true
+ case EmbeddingProviderInfoKindOpenai:
+ return true
+ case EmbeddingProviderInfoKindVoyage:
+ return true
+ default:
+ return false
+ }
+}
+
// Defines values for GitRepoWebhookMode.
const (
GitRepoWebhookModeAuto GitRepoWebhookMode = "auto"
@@ -263,6 +305,24 @@ func (e JobStatus) Valid() bool {
}
}
+// Defines values for LoginLockType.
+const (
+ LoginLockTypeIp LoginLockType = "ip"
+ LoginLockTypeIpEmail LoginLockType = "ip_email"
+)
+
+// Valid indicates whether the value is a known member of the LoginLockType enum.
+func (e LoginLockType) Valid() bool {
+ switch e {
+ case LoginLockTypeIp:
+ return true
+ case LoginLockTypeIpEmail:
+ return true
+ default:
+ return false
+ }
+}
+
// Defines values for MeResponseAuthMethod.
const (
MeResponseAuthMethodApiKey MeResponseAuthMethod = "api_key"
@@ -356,6 +416,24 @@ func (e ReindexEnqueuedResponseStatus) Valid() bool {
}
}
+// Defines values for ResetLoginLockRequestType.
+const (
+ ResetLoginLockRequestTypeIp ResetLoginLockRequestType = "ip"
+ ResetLoginLockRequestTypeIpEmail ResetLoginLockRequestType = "ip_email"
+)
+
+// Valid indicates whether the value is a known member of the ResetLoginLockRequestType enum.
+func (e ResetLoginLockRequestType) Valid() bool {
+ switch e {
+ case ResetLoginLockRequestTypeIp:
+ return true
+ case ResetLoginLockRequestTypeIpEmail:
+ return true
+ default:
+ return false
+ }
+}
+
// Defines values for RuntimeConfigSource.
const (
Db RuntimeConfigSource = "db"
@@ -419,6 +497,27 @@ func (e StatusResponseStatus) Valid() bool {
}
}
+// Defines values for SwitchEmbeddingProviderRequestKind.
+const (
+ SwitchEmbeddingProviderRequestKindOllama SwitchEmbeddingProviderRequestKind = "ollama"
+ SwitchEmbeddingProviderRequestKindOpenai SwitchEmbeddingProviderRequestKind = "openai"
+ SwitchEmbeddingProviderRequestKindVoyage SwitchEmbeddingProviderRequestKind = "voyage"
+)
+
+// Valid indicates whether the value is a known member of the SwitchEmbeddingProviderRequestKind enum.
+func (e SwitchEmbeddingProviderRequestKind) Valid() bool {
+ switch e {
+ case SwitchEmbeddingProviderRequestKindOllama:
+ return true
+ case SwitchEmbeddingProviderRequestKindOpenai:
+ return true
+ case SwitchEmbeddingProviderRequestKindVoyage:
+ return true
+ default:
+ return false
+ }
+}
+
// Defines values for TunnelBinaryProvider.
const (
TunnelBinaryProviderCloudflare TunnelBinaryProvider = "cloudflare"
@@ -740,6 +839,27 @@ func (e WorkspaceSearchResponseStatus) Valid() bool {
}
}
+// Defines values for TestEmbeddingProviderParamsKind.
+const (
+ TestEmbeddingProviderParamsKindOllama TestEmbeddingProviderParamsKind = "ollama"
+ TestEmbeddingProviderParamsKindOpenai TestEmbeddingProviderParamsKind = "openai"
+ TestEmbeddingProviderParamsKindVoyage TestEmbeddingProviderParamsKind = "voyage"
+)
+
+// Valid indicates whether the value is a known member of the TestEmbeddingProviderParamsKind enum.
+func (e TestEmbeddingProviderParamsKind) Valid() bool {
+ switch e {
+ case TestEmbeddingProviderParamsKindOllama:
+ return true
+ case TestEmbeddingProviderParamsKindOpenai:
+ return true
+ case TestEmbeddingProviderParamsKindVoyage:
+ return true
+ default:
+ return false
+ }
+}
+
// Defines values for ListApiKeysParamsOwner.
const (
All ListApiKeysParamsOwner = "all"
@@ -851,6 +971,21 @@ func (e UpdateTunnelBinaryParamsProvider) Valid() bool {
}
}
+// ActiveEmbeddingProvider defines model for ActiveEmbeddingProvider.
+type ActiveEmbeddingProvider struct {
+ // Config Persisted provider config blob. Shape varies by kind; API
+ // keys are NOT stored — only env-var names are.
+ Config *map[string]interface{} `json:"config,omitempty"`
+
+ // Id `Provider.ID()` fingerprint, e.g. `voyage:voyage-code-3:1024:float`.
+ // Matches `embedding_model` on /status.
+ Id string `json:"id"`
+ Kind ActiveEmbeddingProviderKind `json:"kind"`
+}
+
+// ActiveEmbeddingProviderKind defines model for ActiveEmbeddingProvider.Kind.
+type ActiveEmbeddingProviderKind string
+
// AddGitRepoRequest defines model for AddGitRepoRequest.
type AddGitRepoRequest struct {
Branch string `json:"branch"`
@@ -1024,6 +1159,40 @@ type DirEntry struct {
Path string `json:"path"`
}
+// EmbeddingProviderInfo defines model for EmbeddingProviderInfo.
+type EmbeddingProviderInfo struct {
+ Kind EmbeddingProviderInfoKind `json:"kind"`
+
+ // Schema ConfigSchema as JSON — describes the form fields the
+ // provider accepts. Shape is `{fields: [{name, label, kind,
+ // required, default, enum, description}]}`. Hardcoded React
+ // forms ignore this; it's exposed for external tooling.
+ Schema map[string]interface{} `json:"schema"`
+
+ // SecretEnvs Env-var names this provider reads for credentials, with a
+ // flag telling whether each is currently set on the server.
+ // Used by the dashboard to render the missing-key banner
+ // before save.
+ SecretEnvs []EmbeddingProviderSecretEnv `json:"secret_envs"`
+}
+
+// EmbeddingProviderInfoKind defines model for EmbeddingProviderInfo.Kind.
+type EmbeddingProviderInfoKind string
+
+// EmbeddingProviderList defines model for EmbeddingProviderList.
+type EmbeddingProviderList struct {
+ Providers []EmbeddingProviderInfo `json:"providers"`
+}
+
+// EmbeddingProviderSecretEnv defines model for EmbeddingProviderSecretEnv.
+type EmbeddingProviderSecretEnv struct {
+ // Name Env-var name (e.g. `CIX_VOYAGE_API_KEY`).
+ Name string `json:"name"`
+
+ // Set True when the env var is present (and non-empty) on the server.
+ Set bool `json:"set"`
+}
+
// Error defines model for Error.
type Error struct {
Detail string `json:"detail"`
@@ -1405,6 +1574,38 @@ type LinkProjectRequest struct {
ProjectHash string `json:"project_hash"`
}
+// LoginLock defines model for LoginLock.
+type LoginLock struct {
+ // Attempts Attempts currently inside the sliding window.
+ Attempts int `json:"attempts"`
+
+ // Email Lower-cased email; present only for type `ip_email`.
+ Email *string `json:"email,omitempty"`
+
+ // ExpiresAt RFC3339 — when the oldest attempt ages out and a slot frees.
+ ExpiresAt time.Time `json:"expires_at"`
+
+ // Ip Source IP the lock is keyed on.
+ Ip string `json:"ip"`
+
+ // Limit The cap that tripped the lock.
+ Limit int `json:"limit"`
+
+ // Type `ip` — the per-IP horizontal-sweep counter (many emails from one
+ // source). `ip_email` — the per-(IP, email) counter for one account.
+ Type LoginLockType `json:"type"`
+}
+
+// LoginLockType `ip` — the per-IP horizontal-sweep counter (many emails from one
+// source). `ip_email` — the per-(IP, email) counter for one account.
+type LoginLockType string
+
+// LoginLockListResponse defines model for LoginLockListResponse.
+type LoginLockListResponse struct {
+ Locks []LoginLock `json:"locks"`
+ Total int `json:"total"`
+}
+
// LoginRequest defines model for LoginRequest.
type LoginRequest struct {
Email openapi_types.Email `json:"email"`
@@ -1620,6 +1821,28 @@ type ReindexEnqueuedResponseMode string
// ReindexEnqueuedResponseStatus defines model for ReindexEnqueuedResponse.Status.
type ReindexEnqueuedResponseStatus string
+// ResetLoginLockRequest defines model for ResetLoginLockRequest.
+type ResetLoginLockRequest struct {
+ // Email Required when `type` is `ip_email`; ignored otherwise.
+ Email *string `json:"email,omitempty"`
+
+ // Ip Source IP of the lock to clear.
+ Ip string `json:"ip"`
+
+ // Type Which counter to clear — matches the `type` from the list.
+ Type ResetLoginLockRequestType `json:"type"`
+}
+
+// ResetLoginLockRequestType Which counter to clear — matches the `type` from the list.
+type ResetLoginLockRequestType string
+
+// ResetUserPasswordRequest defines model for ResetUserPasswordRequest.
+type ResetUserPasswordRequest struct {
+ // NewPassword One-time password the user must change on next login.
+ // The admin shares this out-of-band.
+ NewPassword string `json:"new_password"`
+}
+
// RestartAccepted defines model for RestartAccepted.
type RestartAccepted struct {
// RestartId Opaque ID; future versions may expose per-restart progress under this id.
@@ -1760,9 +1983,25 @@ type StatusResponse struct {
// Backend Backend identifier (e.g. `go`).
Backend string `json:"backend"`
- // EmbeddingModel Hugging Face model id (e.g. `awhiteside/CodeRankEmbed-Q8_0-GGUF`).
+ // EmbeddingModel Active provider fingerprint — formerly the HuggingFace repo id,
+ // now `Provider.ID()` e.g. `ollama:CodeRankEmbed`,
+ // `openai:text-embedding-3-small`, `voyage:voyage-code-3:1024:float`.
+ // Used by the dashboard to compare against each project's
+ // `indexed_with_model` and render the stale-model badge.
EmbeddingModel string `json:"embedding_model"`
+ // EmbeddingProvider Active provider kind: `ollama`, `openai`, or `voyage`. Empty
+ // when the embedding service is disabled or the fake fixtures
+ // substitute a non-Service implementation.
+ EmbeddingProvider *string `json:"embedding_provider,omitempty"`
+
+ // EmbeddingProviderManagesProcess True when the active provider owns an in-process child
+ // (currently only `ollama`). The footer renders a green/red
+ // liveness dot when true, and a permanent green dot otherwise
+ // (HTTP-only providers have no process to die — Ready failures
+ // surface at request time, not on every footer poll).
+ EmbeddingProviderManagesProcess *bool `json:"embedding_provider_manages_process,omitempty"`
+
// LatestVersion Latest released server version (without the `server/v` prefix,
// e.g. `0.5.1`). Null until the first successful poll completes.
LatestVersion *string `json:"latest_version,omitempty"`
@@ -1790,6 +2029,15 @@ type StatusResponse struct {
// StatusResponseStatus defines model for StatusResponse.Status.
type StatusResponseStatus string
+// SwitchEmbeddingProviderRequest defines model for SwitchEmbeddingProviderRequest.
+type SwitchEmbeddingProviderRequest struct {
+ Config map[string]interface{} `json:"config"`
+ Kind SwitchEmbeddingProviderRequestKind `json:"kind"`
+}
+
+// SwitchEmbeddingProviderRequestKind defines model for SwitchEmbeddingProviderRequest.Kind.
+type SwitchEmbeddingProviderRequestKind string
+
// SymbolEntry defines model for SymbolEntry.
type SymbolEntry struct {
FilePath string `json:"file_path"`
@@ -1823,6 +2071,14 @@ type SymbolSearchResponse struct {
Total int `json:"total"`
}
+// TestEmbeddingProviderResponse defines model for TestEmbeddingProviderResponse.
+type TestEmbeddingProviderResponse struct {
+ // Dimension Embedding dimension as reported by the provider after
+ // Start. 0 when the provider learns the dimension lazily.
+ Dimension *int `json:"dimension,omitempty"`
+ Ok bool `json:"ok"`
+}
+
// TunnelBinary defines model for TunnelBinary.
type TunnelBinary struct {
Installed bool `json:"installed"`
@@ -1966,6 +2222,11 @@ type UpdateUserRequest struct {
// the last enabled admin when set to true.
Disabled *bool `json:"disabled,omitempty"`
+ // LocalProjectDisabled When true, the user may not create local projects or
+ // index/reindex any project. Search and workspace creation stay
+ // allowed; admins are always exempt. Has no last-admin guard.
+ LocalProjectDisabled *bool `json:"local_project_disabled,omitempty"`
+
// Role New role for the user. Refused for the last enabled admin
// when set to `user`.
Role *UpdateUserRequestRole `json:"role,omitempty"`
@@ -1989,13 +2250,21 @@ type User struct {
// Disabled True when `disabled_at` is set. Disabled users cannot
// authenticate via password OR API key.
- Disabled bool `json:"disabled"`
- DisabledAt *time.Time `json:"disabled_at,omitempty"`
- Email openapi_types.Email `json:"email"`
- Id string `json:"id"`
- MustChangePassword bool `json:"must_change_password"`
- Role UserRole `json:"role"`
- UpdatedAt time.Time `json:"updated_at"`
+ Disabled bool `json:"disabled"`
+ DisabledAt *time.Time `json:"disabled_at,omitempty"`
+ Email openapi_types.Email `json:"email"`
+ Id string `json:"id"`
+
+ // LocalProjectDisabled When true, the user may not create local projects or
+ // index/reindex any project (both return 403). Search of
+ // already-indexed projects and workspace creation remain
+ // allowed. Admins are always exempt regardless of this flag.
+ // Defaults to false; existing users created before this field
+ // was introduced are false (allowed) for backward compatibility.
+ LocalProjectDisabled bool `json:"local_project_disabled"`
+ MustChangePassword bool `json:"must_change_password"`
+ Role UserRole `json:"role"`
+ UpdatedAt time.Time `json:"updated_at"`
}
// UserRole defines model for User.Role.
@@ -2025,10 +2294,18 @@ type UserWithStats struct {
// LastLoginAt Most recent session creation timestamp (RFC3339).
// Null if the user has never logged in.
- LastLoginAt *time.Time `json:"last_login_at,omitempty"`
- MustChangePassword bool `json:"must_change_password"`
- Role UserWithStatsRole `json:"role"`
- UpdatedAt time.Time `json:"updated_at"`
+ LastLoginAt *time.Time `json:"last_login_at,omitempty"`
+
+ // LocalProjectDisabled When true, the user may not create local projects or
+ // index/reindex any project (both return 403). Search of
+ // already-indexed projects and workspace creation remain
+ // allowed. Admins are always exempt regardless of this flag.
+ // Defaults to false; existing users created before this field
+ // was introduced are false (allowed) for backward compatibility.
+ LocalProjectDisabled bool `json:"local_project_disabled"`
+ MustChangePassword bool `json:"must_change_password"`
+ Role UserWithStatsRole `json:"role"`
+ UpdatedAt time.Time `json:"updated_at"`
}
// UserWithStatsRole defines model for UserWithStats.Role.
@@ -2280,6 +2557,9 @@ type WorkspaceSearchStaleFTSRepo struct {
// ProjectHash defines model for ProjectHash.
type ProjectHash = string
+// BadRequest defines model for BadRequest.
+type BadRequest = Error
+
// Conflict defines model for Conflict.
type Conflict = Error
@@ -2307,6 +2587,12 @@ type WorkspacesDisabled = Error
// bearerAuthContextKey is the context key for bearerAuth security scheme
type bearerAuthContextKey string
+// TestEmbeddingProviderJSONBody defines parameters for TestEmbeddingProvider.
+type TestEmbeddingProviderJSONBody map[string]interface{}
+
+// TestEmbeddingProviderParamsKind defines parameters for TestEmbeddingProvider.
+type TestEmbeddingProviderParamsKind string
+
// ListApiKeysParams defines parameters for ListApiKeys.
type ListApiKeysParams struct {
// Owner `all` — admin-only, returns every key in the system.
@@ -2395,6 +2681,15 @@ type WorkspaceSearchParams struct {
MinScore *float32 `form:"min_score,omitempty" json:"min_score,omitempty"`
}
+// SwitchEmbeddingProviderJSONRequestBody defines body for SwitchEmbeddingProvider for application/json ContentType.
+type SwitchEmbeddingProviderJSONRequestBody = SwitchEmbeddingProviderRequest
+
+// TestEmbeddingProviderJSONRequestBody defines body for TestEmbeddingProvider for application/json ContentType.
+type TestEmbeddingProviderJSONRequestBody TestEmbeddingProviderJSONBody
+
+// ResetLoginLockJSONRequestBody defines body for ResetLoginLock for application/json ContentType.
+type ResetLoginLockJSONRequestBody = ResetLoginLockRequest
+
// PutRuntimeConfigJSONRequestBody defines body for PutRuntimeConfig for application/json ContentType.
type PutRuntimeConfigJSONRequestBody = RuntimeConfigUpdate
@@ -2404,6 +2699,9 @@ type CreateUserJSONRequestBody = CreateUserRequest
// UpdateUserJSONRequestBody defines body for UpdateUser for application/json ContentType.
type UpdateUserJSONRequestBody = UpdateUserRequest
+// ResetUserPasswordJSONRequestBody defines body for ResetUserPassword for application/json ContentType.
+type ResetUserPasswordJSONRequestBody = ResetUserPasswordRequest
+
// CreateApiKeyJSONRequestBody defines body for CreateApiKey for application/json ContentType.
type CreateApiKeyJSONRequestBody = CreateApiKeyRequest
@@ -2487,6 +2785,24 @@ type ShareWorkspaceToGroupJSONRequestBody = ShareToGroupRequest
// ServerInterface represents all server handlers.
type ServerInterface interface {
+ // List registered embedding-provider kinds (admin only)
+ // (GET /api/v1/admin/embedding-providers)
+ ListEmbeddingProviders(w http.ResponseWriter, r *http.Request)
+ // Get the currently active embedding provider (admin only)
+ // (GET /api/v1/admin/embedding-providers/active)
+ GetActiveEmbeddingProvider(w http.ResponseWriter, r *http.Request)
+ // Switch to a different embedding provider (admin only)
+ // (PUT /api/v1/admin/embedding-providers/active)
+ SwitchEmbeddingProvider(w http.ResponseWriter, r *http.Request)
+ // Validate an embedding-provider config without persisting (admin only)
+ // (POST /api/v1/admin/embedding-providers/{kind}/test)
+ TestEmbeddingProvider(w http.ResponseWriter, r *http.Request, kind TestEmbeddingProviderParamsKind)
+ // List active login rate-limit locks (admin only)
+ // (GET /api/v1/admin/login-locks)
+ ListLoginLocks(w http.ResponseWriter, r *http.Request)
+ // Clear a login rate-limit lock (admin only)
+ // (POST /api/v1/admin/login-locks/reset)
+ ResetLoginLock(w http.ResponseWriter, r *http.Request)
// List GGUF model files cached on disk (admin only)
// (GET /api/v1/admin/models)
ListModels(w http.ResponseWriter, r *http.Request)
@@ -2514,6 +2830,9 @@ type ServerInterface interface {
// Change role or disabled flag (admin only)
// (PATCH /api/v1/admin/users/{id})
UpdateUser(w http.ResponseWriter, r *http.Request, id string)
+ // Reset a user's password (admin only)
+ // (POST /api/v1/admin/users/{id}/reset-password)
+ ResetUserPassword(w http.ResponseWriter, r *http.Request, id string)
// List my API keys (or all keys if admin)
// (GET /api/v1/api-keys)
ListApiKeys(w http.ResponseWriter, r *http.Request, params ListApiKeysParams)
@@ -2751,6 +3070,42 @@ type ServerInterface interface {
type Unimplemented struct{}
+// List registered embedding-provider kinds (admin only)
+// (GET /api/v1/admin/embedding-providers)
+func (_ Unimplemented) ListEmbeddingProviders(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// Get the currently active embedding provider (admin only)
+// (GET /api/v1/admin/embedding-providers/active)
+func (_ Unimplemented) GetActiveEmbeddingProvider(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// Switch to a different embedding provider (admin only)
+// (PUT /api/v1/admin/embedding-providers/active)
+func (_ Unimplemented) SwitchEmbeddingProvider(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// Validate an embedding-provider config without persisting (admin only)
+// (POST /api/v1/admin/embedding-providers/{kind}/test)
+func (_ Unimplemented) TestEmbeddingProvider(w http.ResponseWriter, r *http.Request, kind TestEmbeddingProviderParamsKind) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// List active login rate-limit locks (admin only)
+// (GET /api/v1/admin/login-locks)
+func (_ Unimplemented) ListLoginLocks(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// Clear a login rate-limit lock (admin only)
+// (POST /api/v1/admin/login-locks/reset)
+func (_ Unimplemented) ResetLoginLock(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
// List GGUF model files cached on disk (admin only)
// (GET /api/v1/admin/models)
func (_ Unimplemented) ListModels(w http.ResponseWriter, r *http.Request) {
@@ -2805,6 +3160,12 @@ func (_ Unimplemented) UpdateUser(w http.ResponseWriter, r *http.Request, id str
w.WriteHeader(http.StatusNotImplemented)
}
+// Reset a user's password (admin only)
+// (POST /api/v1/admin/users/{id}/reset-password)
+func (_ Unimplemented) ResetUserPassword(w http.ResponseWriter, r *http.Request, id string) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
// List my API keys (or all keys if admin)
// (GET /api/v1/api-keys)
func (_ Unimplemented) ListApiKeys(w http.ResponseWriter, r *http.Request, params ListApiKeysParams) {
@@ -3276,6 +3637,138 @@ type ServerInterfaceWrapper struct {
type MiddlewareFunc func(http.Handler) http.Handler
+// ListEmbeddingProviders operation middleware
+func (siw *ServerInterfaceWrapper) ListEmbeddingProviders(w http.ResponseWriter, r *http.Request) {
+
+ ctx := r.Context()
+
+ ctx = context.WithValue(ctx, BearerAuthScopes, []string{})
+
+ r = r.WithContext(ctx)
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.ListEmbeddingProviders(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetActiveEmbeddingProvider operation middleware
+func (siw *ServerInterfaceWrapper) GetActiveEmbeddingProvider(w http.ResponseWriter, r *http.Request) {
+
+ ctx := r.Context()
+
+ ctx = context.WithValue(ctx, BearerAuthScopes, []string{})
+
+ r = r.WithContext(ctx)
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetActiveEmbeddingProvider(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// SwitchEmbeddingProvider operation middleware
+func (siw *ServerInterfaceWrapper) SwitchEmbeddingProvider(w http.ResponseWriter, r *http.Request) {
+
+ ctx := r.Context()
+
+ ctx = context.WithValue(ctx, BearerAuthScopes, []string{})
+
+ r = r.WithContext(ctx)
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.SwitchEmbeddingProvider(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// TestEmbeddingProvider operation middleware
+func (siw *ServerInterfaceWrapper) TestEmbeddingProvider(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "kind" -------------
+ var kind TestEmbeddingProviderParamsKind
+
+ err = runtime.BindStyledParameterWithOptions("simple", "kind", chi.URLParam(r, "kind"), &kind, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "kind", Err: err})
+ return
+ }
+
+ ctx := r.Context()
+
+ ctx = context.WithValue(ctx, BearerAuthScopes, []string{})
+
+ r = r.WithContext(ctx)
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.TestEmbeddingProvider(w, r, kind)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// ListLoginLocks operation middleware
+func (siw *ServerInterfaceWrapper) ListLoginLocks(w http.ResponseWriter, r *http.Request) {
+
+ ctx := r.Context()
+
+ ctx = context.WithValue(ctx, BearerAuthScopes, []string{})
+
+ r = r.WithContext(ctx)
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.ListLoginLocks(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// ResetLoginLock operation middleware
+func (siw *ServerInterfaceWrapper) ResetLoginLock(w http.ResponseWriter, r *http.Request) {
+
+ ctx := r.Context()
+
+ ctx = context.WithValue(ctx, BearerAuthScopes, []string{})
+
+ r = r.WithContext(ctx)
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.ResetLoginLock(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
// ListModels operation middleware
func (siw *ServerInterfaceWrapper) ListModels(w http.ResponseWriter, r *http.Request) {
@@ -3480,6 +3973,38 @@ func (siw *ServerInterfaceWrapper) UpdateUser(w http.ResponseWriter, r *http.Req
handler.ServeHTTP(w, r)
}
+// ResetUserPassword operation middleware
+func (siw *ServerInterfaceWrapper) ResetUserPassword(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id string
+
+ err = runtime.BindStyledParameterWithOptions("simple", "id", chi.URLParam(r, "id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
+ return
+ }
+
+ ctx := r.Context()
+
+ ctx = context.WithValue(ctx, BearerAuthScopes, []string{})
+
+ r = r.WithContext(ctx)
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.ResetUserPassword(w, r, id)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
// ListApiKeys operation middleware
func (siw *ServerInterfaceWrapper) ListApiKeys(w http.ResponseWriter, r *http.Request) {
@@ -5965,6 +6490,24 @@ func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handl
ErrorHandlerFunc: options.ErrorHandlerFunc,
}
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/api/v1/admin/embedding-providers", wrapper.ListEmbeddingProviders)
+ })
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/api/v1/admin/embedding-providers/active", wrapper.GetActiveEmbeddingProvider)
+ })
+ r.Group(func(r chi.Router) {
+ r.Put(options.BaseURL+"/api/v1/admin/embedding-providers/active", wrapper.SwitchEmbeddingProvider)
+ })
+ r.Group(func(r chi.Router) {
+ r.Post(options.BaseURL+"/api/v1/admin/embedding-providers/{kind}/test", wrapper.TestEmbeddingProvider)
+ })
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/api/v1/admin/login-locks", wrapper.ListLoginLocks)
+ })
+ r.Group(func(r chi.Router) {
+ r.Post(options.BaseURL+"/api/v1/admin/login-locks/reset", wrapper.ResetLoginLock)
+ })
r.Group(func(r chi.Router) {
r.Get(options.BaseURL+"/api/v1/admin/models", wrapper.ListModels)
})
@@ -5992,6 +6535,9 @@ func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handl
r.Group(func(r chi.Router) {
r.Patch(options.BaseURL+"/api/v1/admin/users/{id}", wrapper.UpdateUser)
})
+ r.Group(func(r chi.Router) {
+ r.Post(options.BaseURL+"/api/v1/admin/users/{id}/reset-password", wrapper.ResetUserPassword)
+ })
r.Group(func(r chi.Router) {
r.Get(options.BaseURL+"/api/v1/api-keys", wrapper.ListApiKeys)
})
@@ -6232,455 +6778,507 @@ func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handl
// const string: with thousands of chunks the chained `+` fold is several
// times slower for the Go compiler than parsing a slice literal.
var swaggerSpec = []string{
- "7L39dts4li/6Krias1bklD6cVFVPj7Oy7nE5TpW7ncRjO919b7OuCJGQhDIFsAHQsrpW7pq/+gF6zYuc",
- "FzkP0U9yFvYGQFIi9eGPpKpn/qqKRRLAxsbG/vztnzuJnOdSMGF05+jnTk4VnTPDFPzrQsmfWGJ+oHpm",
- "/5kynSieGy5F56jzlittyIvfkBm7I8mMKk3khMRXPxy/6M6kNqOcmtlBPCBXjEUi5sIwJWg2zPGjemA/",
- "e0HNLB5EotPrcPtR+06n1xF0zsp/KfaXgiuWdo6MKlivo5MZm1M7I3ZH53lmH/12/K/py+Tf2Av69eS3",
- "h9+87PTs23bIzlHn//sz7U8O+//2488vfvPpf3R6HbPM7UvaKC6mnU+fPtlBdC6FZrDwEykmGU+M/f9E",
- "CsME/C/N84wn1BJg+JO2VPi5Mpn/odikc9T5l2FJ0iH+qoenSkmFA9WpeMm0LFTCCM0Uo+mSsDuujSZd",
- "NpgOCJtTnhFDb5g46Hzqdd5KNeZpysTTT+y4MDMmjP0qS3tkXBiS0eRGEzNjxO8IUTJjdmJnImV3TH0U",
- "9JbyjI7tnjz1DGFMLqZEM3XLE0aENCSRYsKnheUWmBYyHX7jyWf0UcyoSDOWwpSYIgyf7HXeS/NWFiL9",
- "jAxlqTGBMT/1Oh8FLcxMKv5X9hnm8I5rbTdGKsLFLc14So4vzsgNW+JcciUTpvXnYZN3NJtINbfMyv5S",
- "MG3IWKZLO7e5m2bg5glnWartHP8o1Y3OacL0Gw7z/Cw756bh+ZnrFZYmUhAz49qzVzeR87kU2ZJQEQkm",
- "ErWEj/Vv2JKMpWUAyrNCMZIrdmtPs5iSKTezYjwy8oYJTSZKziOx4FYQ9ixRKMmpMpxmfWNp9YblmnBB",
- "hBT9XMm0SOwABChxZ/TBIBInM5bcgFhw08rkVBMqLMG1ocpY+W6X6yhgCXScpt9zc8lyeYmbApePkjlT",
- "hqMMHisqErh35lycMzE1s87RizXZ3eu4BRUqW7+kZsbk+mg4xGcGiZwP5UIwNVQsl+Tj5fmg0/DFXGbZ",
- "CC6sW5qNNEukSPX6xz/A/9CM5Ez14YP2RZLQlAm7fYK4V0n3cCjn3BiWkn/87e+eTimb0CIzB5U52EGn",
- "TPlJcDEdMRH4rz78KfxA3HNEL0UyII6JNFmw8UzKm9Fcpuz1s9Rx8bNIdN0v5E8fLv3LB6+INDOmFlyz",
- "IODt9nNNFLPXNUvJNy9f4k3t5jqWMmNU2LkCM414uoFGPLXqASXaSMvJ33PzQzEmF8fXpFueP6lIrvgt",
- "NXYGudQHjdtTXRqOCHTsHHXmVBQ06/Q6TBTzztGfyz/QwshOr+Pp0PlxXQmoKhp/rnJVz/Ni+ZIcW6LY",
- "yVhOVrLI37H5mKlWbi40U45Am8f1DzaOlfPfs+X6xxPF7C09ojCwlXb2/zopNaxv+Jw1EbFxLr1ORrUZ",
- "FXrzx0SRuTseFbINX+G5/coeLxR0pxdQQ2xYABzvUTu5e51csQm/W2fVN1znGV32QaDiQ5Zl7XGYFFlm",
- "ry+nlsUJvxvRF+OXydfpN7GVgedSTAkTspjOiJFEsUROhT1MXJDMKnQ9omdSmfDMjBrCTSQSKqyMty8I",
- "bVSRGBhQKj7lgma1A1cuQbFbecOqy6scRvfjAzZwhSV52lmlq9uAQMxelQfL+bUz8Qk+vs7LNOejG2Ty",
- "TbeoOwqfeh27N/6N+oZezxjJM8rhqoLtu6VZwQbk+fNLZgolWErYHU1MtiRSJGzw/Dm5suIJdkazpFAs",
- "W5J//Md/2j1R7kImC7rEPTaKs1v7MMmoYapxr1ZI6VdXmXY7jc65NpfOLGklFPw/N2yudyeZG48qRfHf",
- "0tCswkzhFmqeve74V5rm/p2URhtF8ytDTaHbFyAYS/Vo7B9v2D9VMLKYMQFHwrKeJgbuPK4Jm+dmOWi4",
- "jVbmvDpK05RPZlRM2QXVeiFV2irDk0IpJqxhiw/uoJsItqg9vqonCz4v5uS3YD/TxNrdA/JekiLPmSJj",
- "q73bJVYG+e02Dlub5MokGtcPhxH5o3X1XuLWl/BDMaeiP1GciTRbkoyOWWZF3UJY0Wf3LaV6NpZUpQNy",
- "XRGlkYDDaLdyygRTVho4xaivecqcAtl0TOGcbST8Kg/Yqbcv/Hu46q+tDvOEq982Z6sfy5w5PTNXLEEB",
- "iRJ6xfSdCqtFIUWdNinkgqRM8VtmdTaaEfwcaPhO3XqmI/Gn/gdr2vev8Ffv9iAzRlPLc0uSUFQovz+9",
- "JkN76siCG3tlsUjowto9LCWg8fWIlnAu++HvMCiZcWE0ocpaoSSTYspUJOwNV2TGTvv3LDeg7Y1pcrOg",
- "KtXECixq+Jhn3CxxRJml8F7GrRzDO1MbnmVEM5ESbpzjyAu/NYKuy7kbdJ1suicujq9rdHVmlbZyHqZ1",
- "fHrV//7kHRmziVQsEjlTmmtrW71C64yjkwT0iJrNCStg9qMJVYozHQlTGxvvp/vxt1/eBj63emorh9do",
- "8nO7xvWIB8/5F1unFNyIzXsGXD7hGdNLbdic2CfJmKFJP+XaMGtUdMcskXOmSYr6HfolGw2LOU1mXLBG",
- "Q+aCqb77nXz8ePaGBJYfL2G7T87PSBcO2/8/HCT8blh+7WBA/jhjIhK5YpoJVPGcH9Ryy/mHk+NzEHjc",
- "8llqLXWzBI3Fqhx0zsAXkUYikwnNjn4uP/3p6OdApU/2OIIdTucMqSEFSflkwuyVEAn3mh7iXZpK5j0M",
- "WcZTNiAf5hzPJbtDxxmaYS1aqJ8FiL11ikk9+EFqY6ffPfCaNPdOO09Lq125nYETM9iqQ5Vc0c5ZH/UG",
- "Wwy8qjXdGP/SZCUJbjjNNtzhHwRq1cQ/AssUbAGCkcwLbeztLqZWIJAJOM0zOeViEAnLxDSdc0H0jFqj",
- "HcSHLExfTvpjKtI1UfDbJmNAohvN27zwxU4PLMntdq5f+tpK3YfbaRx8ZLuKlBbPwEQx1rdbQSoPNJ7P",
- "RxVBb9gE1izFmWHzBi4R6SjjgjXpxb2OFTtBNK1N9IaLNvNaTAs6bTZd20drtXZzCspe6++aTwU1hWLb",
- "HQ/uEoGpV9fn5tUrCVJZxmbCtjLGfanH59zUPD4vDuF4WC26c3TY5EbTy/lYZvtyjXtr2/LaTBvFrKaz",
- "u2m2woubTLRNq11ZhJ/FJmvtDVenwqhlyx4lskB/92Yit2zlynwcO1U+3DSjEKtZlSXGSe3Ng7jnmr78",
- "lmdeB9LAPWsuZ6bNSCcSj0u4HSaZBK+G+6Ao5uNdhMDGsz6nJpmx3TnEzv2dfWedOVYIUD25lQWVQ7aR",
- "Bj+/bvXOCnEzwjcaFlKJiaz9tlmECqYNS0czvsdBeQ/v/MBN0xnZY+cgLrFhbnj+2+TqqrAoP1aTkp40",
- "fma9Ki3bduGCLjNJGxxjFUKvRB2v3/Z/S6z9MCDfcUHVEpVia4gWWQoa3pgRXYwxBNF4tbqvj2aNsf6r",
- "H477L7/FUH/Kp9agkRMSu5fixi9uZP/WQ6P5X9meYs7xeknt2lrcJ9vIjaKgWQPY/XivOJKZwYiJfwQC",
- "a6LIMsInpBCp+32wtye2ditvuoPt0q4YVcms9Q5ev0xfbr1M/1Iw1eBovSrGOGGCMiYldEq50IbEYcbx",
- "YE+jFsfatrjHuoFXeOEz3sBvpUrYlZF5+2ISKhKWNQYBSx8pFYQmht9aG6vvIuxobhHNtOZSkAXVmBJg",
- "bU2IPeBnB+QtzbT7jpBmZrfSPhysta41an6S4/5fClawSCQZo6LInTtGUQF2nGaMxD/JsR7Z3xVLITbS",
- "GDGsPrW+qhOrHVgRkzORcjEdqkIIO48kk4KNINb6Fc4O/2E/B+6VSCyYYiRlGbMnEOxxO3eYN5i2YGPZ",
- "l2pTqyozaJhv4xjnvFh3wIbNWlll0+a7IHgDBexCyVc+jEvmzNCUGgpLoKI00LtTbvpAlvTA+xQGkTh1",
- "DtMXRy+C+w5PpyWjz8EiSi5eEXAqlH+b0VsWCSGJm5x9CGm1EoAojBy5+a0v4JxNabIkNOPAdIrE1bAt",
- "ef2aRPCFqBMPGjmkjP+vX1b3iHfWswSaA5DMq567xSv1bMdYJbszI8gpoA3X9/FYy6wwjIAXIXAneH7Y",
- "nSGp41sKwfoBeW/vkQW6k1zon4NzCwLbA/KOUQ3JIoH3mUi9+8XO2wkFVQjc1fuFeK1Mb9EWXvymbxWF",
- "qx+OX1TiqI6/4DLokUKzlHBBPl6e64fkYFxsSb1w9FrPuohE9+TsT6M3p2+PP55fjy4+nJ+Pzt5fn17+",
- "4fj8YECOswVdapJkdJ6zlBQ5Mehbm2RSKvfyu7P3qy8CRVuIt09yxx8h7GXfRo/ezIoQXKQVQGmRMUUm",
- "DDT6CtNIAalAnm4ot2kGsgLuBiO9SMFTKaToowvKJVxE4l1hCpplS8LukqzQ9i2QILXz+3+9JmVSSZuQ",
- "r255Q/QL7ZEgeAbBsQeXSUKFFDyhWSSiTmP+zv9EERF1CLJNi5uympyyla2LPN1btKzmozw8+aRGuOpZ",
- "6zXmpfTqsnhlRiux+coKN9xI7fF5O5J3r4+ENK1hMcVoCtFaxai22gdoKdXXrQjQZGJ1j0YZsPLwJu2n",
- "xpxWdXlmX35Gjt+/qaSmRUIXiVWMJkUGwZkwD/sMXLTA6hgua2PrKTegdWzTEPzlfg+dotxCzRLFGq6N",
- "H94dnxD8sZbQIK38k4LgnpOv8A+3nEYipF4Pf7bM9GnoxuhzMZGD58+bj4+fSGN+3UUxzniSLe1mJzPY",
- "7YsPV9f2ysklFwYTJZDKViq7tC+8vlIJeqbTcDQzRU7wzGTLXZIpPFErO1Kf7hoVWxh+VoyPk+DqWrme",
- "/ZwpPgGccnF8beWTVXgxVgi+frkAHdU/wHUkQgAbHP89MpFZJhcYNGK3TC2JVFP7aauhW+rdcopB16FU",
- "U+1iBCGI/EwTmqZ44U0yuYBYM0QbMdWIkiuWscSE2CTm8uVScyPVkuQ8uWHKh4nssaZGKlhKqqwmz4WR",
- "hBKds4RPeBIJOz1ryTEKOoRi2RIyezG6TScTnnHIgtV9Op0qNoU4/i1nzSrjLTVUtSthcsobIgVuA+BX",
- "0gVSCzpn1qi209NZMW2O53mnVf1zEURGoo6zBnCz4FZ5RaKOVFP3k1RTKrjG1eFqvGSH0ErPPrtdluOi",
- "3FPtDNhsBhxXd++WI4/gFmEe5cXx9WCNzE7FGZUqdFPwNJfPtNeGCD76qp6zYLW3/oRnGQa03XUruMgL",
- "460KruspOsBjmlDUR4IOmnFtWu7nbYFnyJRqzr9AXcCHv1dfnJl51sprLs+0KYVu1ekSxu+tUrb8TGW0",
- "9j2+9vkHv/D0zfZwUiVDpboP3zFt+mwykcq4DBDYb3Jx+QIZ1TIJNZD6YLkBUzp8CF2/igRk0Fnxwqi2",
- "OqHMC/snZLBqUopLZHGZKf6eiUQwcstsClD89ssRacp8dFvv1l7TprZs9eYEPszA39lDVWWhB+TwuVE3",
- "eaQgRvI4bLoxAvy2MfBLTue5WTqV3imNY82EGexxDlo5eH/9fgNLVJezp5ZtSXyWbmaQqX1oxNM6j+zH",
- "weU3WqexwyT24FLgnQfwpxtvK39ivn2DfZKme/LoHukge6Za9PZP+++FwWGsXrmeLZTYvItzeGbPbXQk",
- "fsBm+mE37eYPjGZmoyef6ibpccUMptiBiIg1ZBvH1qCMCzGDjy6bI1P4aHUfwWgOb23X6dwXmpYDVYnf",
- "sSnfkP1QZFkt8AIWcK/dA7TgOdNYGVrx3hI7C+ZUfavMB+vD+ftbsqM3Trl1FwrRVk+Bmij4J8IR5Jjb",
- "c1G/8DbeDp13NEd9ccIzl772j7/9nfjYo5wQl9ucLftO+3WRPndnRCJoop5EM6qJALVjzJhAzydLSVcq",
- "EtttAA0oBodBTrVmaT1g4Wm0GtZBYqwuvZUdTiAksGN8Z4s2Wj7bOtxbnjG9Mfdmv7iYD0lD2sLdGb72",
- "7eG6WCiZZJ9AX6AmzmzbslqJOCvEjR4lpeNqcywTRhtZ0zvf43kXWGPp6D7xwJUxe6uTbhtlA00E17MN",
- "CXgQBgM/4l5axM576ST7COedcp3IW++r2ydQiqNtXefjbn4g8/YX1u8Me1iAujtfF+vDrjFAKwEulJwq",
- "pvXpbWMOyAfBCFT4+rqD929+d/XhvdWiGZ0T5opPx0sSg39uCJJwCPOJnTuuapgxkWoSHwOjHpFqsfNd",
- "X6Q/aSlidHzFMGqMpdORsAyg+JwLahg6DW6p4lQYV2DqSqyhNMDbeCmhGiy/WypMk9doTE0yG/nMkPW9",
- "QRpu+q3KGOvPWCUlHeG5CDogF+Y33zTGh5nfAs8JkOMASUDhCI9g3PKfMERa/juVkCGEv0HUsdeZMarM",
- "mIH5gEt2T+EDTerlhNb1sIqTGj4Nu9yewFoXf3uIvPVH50zrvZN9NigVRt/TPsPd2XqOzsSkwd3mfyU5",
- "XnnI45hW0fdZFI6jfQ2H8+MCY7/CUzTjVjHgCc36E5plY5rchLdAZfWvxisUjnuRcH8DWsc9qAqI61wc",
- "Nx2SfSWgrxML6sCKMiY1VKVaaYDZZFhY4TSoHhFswbRBv/YrFx/9ekDOmdGEko9nkdAzuSAZv4Xw9YKq",
- "lMwlgAekBZj2FELQztxHh3IkNpBu32ofltHccm0ldlzykyzGGWvL6dznIrvHXVLZ4B1Sa2dU12xOuyn8",
- "1q65t/EO2nC8Pm07He0Xbe6e2KY3rh+22iVaZ7aYpxmLIeorZMhWArV9SAIbFCW4zAAAhTA3KXapR/gS",
- "nlX7e6BNPIyD0hwP4wnl+D8upwjfz6g2fVUIgnNEQyR2GUaF0HE9AGAnDEUTOIfaVvRqKUA4XAd2ww73",
- "IOPyd3Lc4PEwhs1zFJhbzryf44O8w/fzA6ZFznyZ9tYhNnm3d0/SmdO70e7EycvE22YDtqkQ85IuCCha",
- "7m3kxRnNGUlZDlqUFCS2o8UDcslEyhShus814U7lCtGWVySV4pkhVOtizgiiARSKNVqkiKaSFtmeG+HU",
- "lAcxwLou7NL0KlxePxDuEPy4IUa3g9cVHumV2nTY25WtXqHNVo/97+R4s/fsJzne3WK2Z/QBLjMYa5O/",
- "7JyLm22Fkz5/pDk/y+o0LkcrDqklMcCzlC4Sn0pYKYWNhGJaZrcMamGNJGXCDtQuCs2UQa2/u/DFYSOe",
- "9iJRTWg5gIRC+K5300CV3BjztmB3Xz9z83C5RXN6F2zQ39TziH+zazINEKORonKTt24P9/DOwAAtNXgb",
- "i/TdLNt4FFzQW1jzo25guBXfdTngO7YBfKIws9GcmZlsysphPmJcRpIXMwb2n5FEF2pCE0aiTiansjBR",
- "h3Td9X1ApLI6YAqoGl2HN+HyI0ogjmc6ZCkbSTI5JbIwRE4O6pe0+6iVFA52o0kAlQGO+ir+wNmijz9i",
- "zJJmGfgRMymmmhjplN36OjH6Caps1IGsPTtF+EzU8fkXC25mdsbUZSkSJQuR9o3iudeHIeMzEhDkBPgt",
- "/IZ+hQWj2mVegzWRcQ1pKRxSUIhzus94riMBuCXdgGEDH8EXsCga0QFOr8kQv3+womXfK9bzMF7s1bgr",
- "bFAji8qUZS31a01F3D+8xbSEszcOKqGSJZvQxO4kVyyBbAtIMUG8H0wzmNvBmhNNmhMcQ2YviEiXPzqY",
- "TosJurihOFvfNMco+F/ZaLw0rNkrsYdrDa5Ol0hY+WorOe1V2OSiTmZslHLVfJ2cnP1p9P33H9+OTo5P",
- "fjgdvTm7RLCDBdVEJ1QIlnrOBuaDaL2Qog8wLiR8nby2rF7SyNUrNFfr29nufi9XeGVb0NR9uVdZdRO5",
- "ymK0fYvmNhfG/eLq2MrF+Mk1keOizHFcJYaSc9qSBXyJKkVK4Ck2708l4BEwBBosz2Oo3QiayfuP5+eh",
- "ZgUARIrdqqp6fkp7nLLtOd2JFIZywVTLSi+sFOACwG1A4PjnSVdODBOE/aWgWU2vapY29zLAKuAXWxN2",
- "7UOooDVCbNidqNeM9NCUwdzk8qFQpCIF04OKuugQUqpIF5HolkAXJGcqIESE4fQBJoY7PBhX3ghuJssY",
- "LellG0BEgoBeXaFLb/QJks+0n0xzDgqqqiMr1CABuSFR9hQcwFAiZx9wS59waw5i1ZaLXZYMDsLTmryR",
- "6Cp24EZxbC+F1aIdKE6uWN/uPkkVnxhiFE1u7FBOYYpEqZ8Yyzsav0E1iTofxY2QCxF1iKKooc2osD/B",
- "tzbWM6zXQu4ZYwJ73lPvIRbpXsAttM68ZaEbZE87+lbZd5hBLdNgn5k8OibK1pHXgA9XqoQByGkmrTLj",
- "KkZypjQgcHSBINnSk+FgRcbOGRU6EjBCVtHEyxoNl4tgqXb6p+vTy/fH52VBWdfMpHZFJDQSPlnbToCp",
- "gx5ZzHgyg5AQ6LZYj+IT8xEGzCeXg74LyewUkoxRQcfymB15dUPhUjOk+QqiObp4EIfu4+V55SQP9gId",
- "73U0M4aLqd6xKuDKP25f/UvGDdt2pV79+zm3UoEaOqaalYLZhKgGiqNSqARJ4UQLuqTYXW53UBup6NQy",
- "7ETuxJNumo96zVpO25lk8Gxz+DaE3CtOXMf/G2NuD84grFbzlJfTmv5QlaoVXvEEqPjB2hIP1wXsqpTY",
- "oMZt9oj5s72z9l2pbHmMwuow/iZP2eq5WXft3CVZkcIxsod2z9trTu9GGPrdH7NgbeTVz21ajz8AK/au",
- "2+YQ0Nvs7sa0jTJ0vsvTe30aTQ+9J2GqA/VW1rQy6dWBNpGsmM9pk5Ogphw+llrzy7lhMIBb3YqdDusV",
- "PN9iK1eFaUMyUD7yJhvfI80swBC1yYdfHqe2ifEglqviu87WG9l4nYhr+7iB0wMoW4tXbP/06Konv3HP",
- "ywd2czPUPrj2+paM59VlNnurwjf3vqBW6LfNU1QZqGm2l4xqzafig711WyMMWzT392zhy9N8nAQAIDAb",
- "uEdcDTlUX21HT9yuAFwywItMWDMqTt21VWYluJcadaZW7CJXZo9eQA8hEopHt+EBVt1ozd/1HpW49G3F",
- "pKvYxCNJu+okrIrpgSNJUTFluqUrwwMgvx7VV1dFAtqOP1X34FXG2QIjFFjhnkh+6xhD335+wL7KIh4L",
- "Lah+RD4jWNAlA5XoVACeTbqh4CP0xqjXFFhLW+FHyCSjt7JQ1dYtC4DzKcQA0+OhnEIzU8ms94DGAOAR",
- "/9/2qdeYRN+tfMdh3vg0HZaO9IzGvlaB4fRXG4/EXCSKzZkwNIsjYS1/zEmVgvV/kuNnGqzVfsoMU5Bj",
- "yqVw9abGOSsjAQgAXQyPzemSuJi1lQIQAqPGLhDAVqwpDAlsfZhlD1/O+ojXCqhdvhmOb6STUM30SpwR",
- "6jmsshpm3ygE98cAWLdaHeXsvekaho0eI6/oEhv1HFeyQdcOCAiZ5hYv9C8FI2dvXpFJYSyRbpnSXAoN",
- "9He+A+yRA18hPokMsNCcV5+n2++uyiwaV4HbegL9kpoC+c4F2+ajrUQHpSK0zTkM5ddliKoZ/C6jczqq",
- "Jy4HUfCiSezhG4m52+t5MZrmxSijS1fcVV9Q/wV5TWiWEXyAdN8xQ7Phycc3xwc9ckhek5OLj6uoyw1j",
- "mJlltYYB7CcyZgg82HdnnxZG9hHjbtDZJu2t1VtuTCIF5qUmy+0UUCyR8zkTKTLsRnld5YzLynv2kEG7",
- "tE11S/7wpWM49Led+tg/bqt7BRc05Ae7vi6+UYBcSR5IqCDK5YiRqPPmu6hDhpGIOqfi1v4viTqVyUM+",
- "QZYhSpSRhNFk5juc/J4tNcJ9YQCgknyPeOJHJF45D3GPxHUmjHtkMGjJPqt7wZoq16xARrKPvPOKKLkI",
- "UQ2yUNwYJkpwRLhjwMPLxO2wQmLwDXNB2GTimOp+YQI/6fGyadKScK0LhwUDM7z4eN0jCc1NHU/LeU4r",
- "VXb7oTiuCqK1w994uteP46bT0yCCAqtvlZ2X9ZO1VYzuJP52EXm7irmdRNWewmabx+7LbNrWvfoIPN1k",
- "AWW+2EY6pPUBuWIiJRSFBKRiMTNULM9ogiFpecuU4iloRpGAAAB8o4cdN+KoE3Viq1xBAj9+/sCe3/gw",
- "Jl1RzJniSfi7kZE4OT89vqx/uwsCy1IDcrs1NAEBASZuyZBUzr3Vsz640iW3lhvGcpfr5CoYqk0ztnLq",
- "9khmA+duj0msc/Ku76xy9u7vVTh9+0sbOX/b603lAldsToXhyRaQWefnboIMyWhyA7lAEO1UMifOACIL",
- "CBeCruUwqwkVZUs2RbTHmx3sVRBy3yh1I+r8au3yHXRywswcIifk7dn5qcvZI13ITwF334FrHVYosYNy",
- "xEUJR97cOiqRmgtGNJ/zjCpulpUmHnXAQ9I9HLy0xI5Exqczg0iGGOWzp0pbjdcomhjy/pz8pWBQoRRy",
- "tA5QekTCHnUjPeDkK6ibJvHh4JuvYhzVKJ4YklhLDa1yooFJmI5EQjM+xl5P9tkTmbJLKm4gO6L/779d",
- "AaRsTXsK9axr5q1hgadAVLgmPE/LWAEW+XHwjVfPVpuND18YgYY1b6IGzbJ+ksnkBnZzCV3qRLLsYbop",
- "NHEiL0jKEj6nGYFboK5btRZJ3QdduYq8/0Qek94KSZqJi0nBjwJvw+5yrph+DOQmrkfuQmuBOfRxe1/p",
- "lFClloj4AOifIIGboXQRrZYxsddEy7f2aeIJL+zUxLMpT7UWyq5Qd2UNNXJt2OXNQWxHyT3iYo53HlDe",
- "Ecbc5OW7mlHFruXmfl0e2We7rzg82TgWT1lC1VVwNa1GlUcTuC42pbQhuHbKcjMjFBES53LOEMJb03me",
- "OZG6+bqrl3c15/s2Fxg3uaUOfWooSWY8g4IWhETXhEJVaherksgwgCcfbJ8j+Nza+q4671Q7yeAgj5lZ",
- "MCYI1l5bEmFJvsadGHovmeugndOFIK6YqgXUBT2F9XhMqMOCj7niLFb5RyhM3ABLa01mZ8GHGto95DPO",
- "yhOtV2GmRk7c0i8Uze6RT9cZ+aqsFeD0gBHjMeOrVZyQNLl9l2nOR86JiVqs5WH7zO2LJklpDRgmGnjw",
- "O/yhmu3pOghPZdyc3LvdS1lMp3ZZb63R5pNJ/WfpwqpAlpOGq7rV6LD//fcf37YMa3UDbaqLXoFzh989",
- "QJ/v1Ok9vaTrS1rs2Y/xx+Ft7FSrXiRweoeDbwcv4gMHym3N2AxBtSEtosTmdWjeroJQ75jZB8QYZZKm",
- "LYjaLr+V1f2V7tyB71cZaJ6ZYgdKLsi3h4dkbidQ6ZAAt7B7iWviz5RVIGdUk0RRPWPpFlDsBta9thdC",
- "FZQ4IGPvIJZgX5pBeh1+qnuG5HSKeSWAyl/f+LiCL08KTA3eLdMPaFnln91gt9oz7Eah2ntbZ2A3aD+Z",
- "seQGOJMnDLbCNbsoOfJ5HAlPBxngiNFkyZYAauAyoJ3/EiQIvm2ZAByoXBPfzd8ea2gSDZOpT4Rjc8UF",
- "h0BYVzND4pOzP43+cHp5dfbh/ejkh9OT349O3x9/d3765jVggFUtq9Cbv42R3GgjGG2b6vIHfPjEPuvu",
- "+laUGi/O1na1LhhXDlyvwUVWSdNrlN6N10Al+ejRGsdtisvvFnDf0B5vUwQdV7Opy9B/9xm8Z59BJO0W",
- "B5Qd5sH+nj0aIz2SB6C2tMfKWljjxc+YuHBdCMEybE/WZGVoQ9sA8HqdORV0uu1O95kHUMMOnxviReIw",
- "hF1nNB/E+XjWrEm3nrVcyVueYmFrSCLPZJFOMgrN3cRUtVxo7bfielozjtGrkKRc/zbCNifDwcr3Scas",
- "7dW2DLjw9fbJnVBDMzltzCKH5e47NX+BbZla+fkNc2tLFigbs6zzyMyV8DTk6tE5S/sGPk1yaI5A/NME",
- "CtxS0NnBL3nQWtZa5TF4CVxbPLlpSyy5L2dibxTNTPvZoiSRQkAyKqbJoc4L+JtdxNb0XQ4Omo9UPVa8",
- "JSq7JXTqtqVXPSquy0nYleqytu18GT675/7/AvavsXuYexui/YEjV3bSxQqMDGG1SASUWXjiFQb+ok7U",
- "sY9BWldovL8DqlTtvK5b9O0aPppb1kIJpxhDFbAmaciSGcKtfThnot7UctXxudmj1NQfAmgWdaxBF+G+",
- "uZYQ5a68CiZAyF9rblktDdvks2psP3dfbkCBs6lTC4E6MGv8dYUkRlEOqPo6o3p2gEZMxm9ZK2xyjbOD",
- "4whSTS1joWfJfmEz6E/pVdoJc7H9lvQeppKT2g/8NQNncGPn39buwugZEclyd3xI7IbXoFnUdqfFPB4l",
- "jie30KDGAeVKUZy5xkNXS5G0QwQ9Tn810j0c+pOw3mQNAvgiW0IFKRfTSeFcC3opEofwAYjdztaNSZdm",
- "WmJyKdUokUIzMz4JTQTjldSBRlu5llQcxmvwqEEBeYlG5ArLx4zcsBwQVe3rg8rgdqV5oWf9VPFbJiLR",
- "haQ377rpwexWJwf9/zGN9OBVZcn/+NvfI+Ho5ju6QR834lf+isTYFwlH9vm7UpCUzalIMYWvlpNa9gJz",
- "46AaWTTmpq7lUpfE2pHJmk/VPRpl7dRQzD5E6Nj7G2VhEjnHsmnwMyL0CFIgEpWtUZgy7Bz/PsE40H59",
- "z3ZpQxVWuYFWGyM52xrgeFVjm23ZMvg2sLB7lyG3D/lRbyh3CdfGtqaHAH5k7TkhSSbFFHNLZ0wYnlDD",
- "BuSSTUBSuGwll7Xn62GwrSGKGwZajv10mzfNt3ZYr72xv4ToKxTZVAcmzeO6jHk3cGxfW4GQ3NI7op24",
- "oUSpQuGVsIM0syrSsk8AgxMC0hrxVzEfNGP01oE1e+UvEpgiVghMhU8H5IJqDW8JV63jk8CkInFl+BiV",
- "RB0JbgYktrwbh7qlEvEHqOMu8rQpeevpDoVuahtyT0yVFkYu/dOxf2hEja+mGJA37o/ATtryuJAGJFXg",
- "bugE5wHhyIdLcnxxRm7Yso1/K+PcH0djD6y7ljQGu9MjZJpRFQ6v/cDt3kvlUVr3rLRXaZzvppL6hmhp",
- "nbe2NX1qhdAGXtjZE2KH+iM3swBxsNEVgt/e5KCrf88aZ1n2YdI5+vMuMG69llitz3YYtTRXDH2+QTBA",
- "ukfqE1x0ifjkKxu3B21v2HK3wRS7lTcs9adKQ4UlAOTvMSKYl9DfrzEPvoqhHbJ2LGPZ/7Ecqw2d56R7",
- "+fbk66+//jervELwjU/K669sYJLJ6RR6Jt+/a/MKUzRv0hoh17nlx0+9TkNAqaFUlCU3LUUC5/bKBKOi",
- "QomP1yc9cvn2hCA9MBbpisbKODH0wb53EcCmlsvBmZwzxWXKEx8hhIly7SOCzd6G4GhoWCn8RhxKfs9v",
- "8bzCITAEaqZu4VL4kPg9agxEu5T6I2rGm6q9ctne7WePmrReh0+FVOiwe2iRmpv2mZjIjcCku7YMrqj+",
- "ta7ANVPOlYOUxsSUcoFwm543rAjpVhswQz1krQfvxfE1mdE0EnDJHQF97ZMHAwI6LzaAqjdlBZ0p9M5t",
- "7Itb4b292gVf23lZ+1ozoTkUs1jNUEkDbTskNgO3jAkLGOzdFvitZd+Pl+dgSVFtGDaWDc0bfc/fBHyw",
- "Hhkyp2bWt6asVz9hm07O/jS6+Pjd+dnJCMAwNCmEVavtjHMFINtkCWWs6OPEEqtdDLeNrYLXu09v4MkP",
- "MGZDZX/4+zpkZr7ikPM0SVnGoaPEx8tzVN/HBc8McZwXiQbPnacg2hxQ5WMJFXWEFCzqtCDjlZVva4JQ",
- "MRLj5OMKUOyAxEhkxMyn2N3BRacc/QeRiEtPVxygwjxf9+3erexpl4uJogHwHOCirWGgPZEcABjPuFm+",
- "ItRvtcuwEIxBsQiJ7XJjzHEX0r/sau64duxWKJb2iK40wk+oeAb2iaO9t0i8hMPhOjUXXg9ou12gORbY",
- "WHzluOiSJVIkPGMf0KHRnALnUtJ8J2LUTUuV1Y50w/N8G+56u2N6pWn/Xp3q3QR3WWSb02hcyWNqg75s",
- "yZXA1Tb+5nxEu+vXbXvShIfj6N048CaF3+3ddm9voEmZ6V5ud8kCGza+sg/effCr6vC6AmZ4fvamn/Eb",
- "K1ag+LwOkdTqLFj5iuD23YDhArGyxvd3xVZ0BESVwX82gOv5NDGp8hl11gYFNT8S0KkNiPOHsss3yE07",
- "dM+DeiNI/7KKfcgNdJoHCMSUGIktgxAlfMfEyS/QFHcXJLoayM+9TOp74ACVx2MP7J9NhnX4YAUfebXJ",
- "u488ZFbXSB0sAi1ZqEdSlkismwqNrkuc90gEGwphe327MeLGDA2nAhC8H5GLiYxEF9XuHgklcj2ygh14",
- "sF6unkqmxTMTCXsBr4DZA5Z9g1tvf/ypfWEzmi+obbhSq7v0yPCHa0zwgBKSnbAPVwd8F5jlMTDBtugI",
- "W0HDNiOCreoUO+0bJsudzApx03CxlfhTe2KxPwDvaSuRWko7L+livawzVI3YI4jlfBi+smqtXTRqvdhx",
- "0dpOWG4K9oOWCps/Dsh7CUAs/vSPpdR4fUCLR5aSLrVG1S2XhSb2v+C0mheZ4fi768dfdnSBRXgM3wx6",
- "MjM0H1OJfSBdgzzMEowE1IjOpDKhxhQu8lzJtEhMHzKlaKKkWM490M5nxsFf4b9doLZwK0vIrR1Y9S2o",
- "aJcuPNrcv6e9c2JbU2wgbEINm5aY+cyHncEYi28hAwgyuDA3BroO2qMuCxP3CDPJgJzBOiBqlC3ByoKE",
- "eLqoe7KIli5AL2hGMItCO9DgjNGbVwRz4Su+lkxOkYPi6rGPy7na6wkG2cWGX9krR5cdyH+BLavuSf+2",
- "Tnau+qh2yPDZATkWS+xZI0ucdQ+PFUcCQLZXm1dbOlqeUnxcGKzYdeWeeDXV7dSyDVeSSVGBNK5VfP24",
- "J003ueRWaNrWAWI8f/ltayU7o8IjoRuZ998Dl3337uW3BN7Q2NK2govf1XwqIjHJwNrBlF6Eun6miR2q",
- "C8pKLp1v67UVnoYpK02usPlQ2gy+A70Eoo4jcR56FaWRkIJk3DAFeII3Vou/ZSqjedQht3pAok5uD5h2",
- "pdsVye3dL9uFWMqEZvuRafWe4CW5gogekGs5Rdc26I5xuRsx+hzNQsLXIIs/0x75g0G4wUgS14R9vOt6",
- "WjDwUUbN6ikdiIi01pSnyorPdCQg0K7ZFIpLseYtQktiaPfrf84pF1EHsmSiTuUvBy0uMFHMRzPeVIx1",
- "gvenm0mF+4A2ulC3MFMXLPCHPRJ4GSc0h/t5TrGVFZARWmRkckwzfztbfb8tZWmrDKptSoPHdzlWHNg6",
- "5SlNlpYv/nzYe/FjcMn97//VH2dMpJat7BpArYjEnIv+nN4RYTc4439lKZ5Gux5gUc8npPu//9frw8G3",
- "B5in5ebTd62cE0am9vZX1K7UKh/WMok61zIPhW1RJxI5FYCFpYwO4bcKpMs2Ntssu5AFV2lV2fdeVTbV",
- "j+AOAm9bQ/L97YOqGttgI6AIx/YJTcD/uQwoF5UbCG98B8MRsrUhlcPes5FwHXmrSALudCVSqSI31ZY8",
- "rm3VAWwo9AQ0XjCVrhTuO5TR6VQxywjpq9D5DcaxmkMt4HEjsKEJc6oiJM9Ao0xfCLpHb7J2ZasJsBvv",
- "zc1khXOP3d+8b6Zc7rgwZMEUs/c1HCMr1CKxdHEKgLAkUmGDjfJidx0ySbeaR+T6WEYCNxvpzFWALAGM",
- "TprnjCoiBSI3LdFFHonY9U/0eoV3tvFJUMNzCZFMRtPl/QlaVZ+aKLqhyLU8/iAbXFv6lSuGuItaO8sC",
- "tsaqmiuEL80hrn04FTvJgyvMksHuLhMmEnLiPsZFym95WpSC2E6EzPh0ZpkZZXT2EOq0W/na0IyNJkbv",
- "wG2Wo0JrmkoYHMTxnOPZ7fru4BOj4wOA1wOL+Qj44pliJUNCThGIuEg4YTB2OZQ6p0ozMqPZxB/mGV4g",
- "3MEzOxsvElYU0Fw7bxLNplJxM5tDrK9QrI93xISKviyMV+vtkMzqsUwPyLXiU8jmq6ayAnyhkZCBObEs",
- "br/+9voqgo5ZZZ/wxBuUJRMAT8+oJmNrIbtvWqXN44syItiC4Gbdf1ev7Na9vb5qY/rW9taQMvwf/xlw",
- "iCYyy+RiQGIgLP5WrgbN4pRMrGY3LkwkfLNLh6qLRfYBHCpGJKcBiR1Y7ciZe2UkzHO5l/x21ylYaLpi",
- "sMNlwFJopok3Akpov5VdzRiJq1dQvIKECwnHsChoVFCbzc6x/1rZsLtHd7iLa7uzr0W3SYtYHxvq3ZPC",
- "avdXllWckWM3Rx0XjZ3GMM0IEvowtT22D0rF/wrpQEfkO3ibRMXh4dfJydmfRscXZ6Pfn/4/8AcWu6bG",
- "cwj7w6OlKjQzJu98+gSdyCayQRO8vr6ALAVvYscJv3PoB3FpsgBiFx7HlLK5FINIRMIqbQuuIAN2TuFC",
- "Hi8N67v+FDRRUusVOAj9CoepVIvHkcBsUy5IPKQ5H96+GOKGx8QAhHNFVmeuUDOuF6DHED+JBAUhsaAq",
- "1X3UDqiBmAkm8pGMilTD7P/lX8hxmVTJpYAlLSTJqaJZxjLIKIbMA19MYIUhnVea00Ex+5F9sU+eP/9O",
- "yQUkbQ5L2/H58yMSI4iLW5n96hAyw2I0uiDtkHwVCVImdQLcqLZq2A/G5FAnkUh5w3GDfF5WjIqz+wUy",
- "SO1lRiBPZU7twrJsiclCY22VN2FgBX0X+HYKnR6QK59Zp2SW2U9MpLJUJC++ISld6tLuAkXEY0rhwk/O",
- "z8iQXL35Pax2E/e6/DHHuXbP3L1lT8CCajuyg1q1N3+dcDnv37Cljh2GLaQvW/uuD511MWnfmupjZj/j",
- "0/jKGz1blu11AS629Li4xoHAGK4cyrcaAIw+5AUvBw6OSAyNcWeMZmYW99w/U5lo8JjBv2TOBM35YEnn",
- "WXikygRjKY02iuZ9x+321TZesVuEydmAFHH88fqH0ZuzK0SIQJR1fcNzVxiDrjV7dcJ9GNomdFN2yzKZ",
- "IwKTZSvM1lhQBXAWXLtkwgMgxR9Xk6EMtbYYtmvz2d6YqIxnnhtPJB0JmOh3Hz5cX11fHl+Mjt+8O3s/",
- "On13fHYek69I468Xx1dXf/xw+SZGCFJ7UZfJfZi1351IlaC/y53pcGqkcE8CyQ4G5Jhgfz43Fyc3YzAf",
- "pCCUTBTTs7ILmjUp5jn6xK2yRDQXU6utx0zc9sN+xT43tJoaSt0EvXDx8TWapopBgjwwl/trHPrCxGjS",
- "at/0E/N2mNPzMP+bjCuBOy4i8fHy3Ps6NNz9IltC4oq3tN2RKJnY0BtGKIl/tmN+isnHy3NrYCs6Z4Y5",
- "rEfXe/P580ljL6J4pRlR/Pz5IBIn2FzVbj36kLzPdxgwan6genZhl+ppc2UUo3NgOOeDtD/Ued+/PcQZ",
- "D+HJISCux2QmhSwUTjfGbMWYzBhNmTqyCixYIP6XIwIhDJTyw7u+SH/S9sbQC45mkzMswV4HDPdICLbI",
- "uLAaK2A+sJRomDPQ4cxO5cIh1Z/eMmFiggqA7oVehvGMUWXGjJrYnkJh3Fl8cegL5AbkQ5aGnqXoPGIi",
- "JUISnHgkcElgBMbVRcACDsiUoYqOXO64tf+7qw/vq25gIPmp1eC0/cexd6KHZyCpubzexjJdEj2jOTsi",
- "8c+Rq4CMOkck6qAYdy5+FONR55Pd2JpE9KyEkN13djFciuBeKgQ+tyS3VHFrkZUA69kyEj4mbUdHvz2O",
- "PhgM3GhWxeEGgLdKjcUey04FU6Fz+wJSNFAQd446Xw8OB193KiChQdDakzss20ZPG8veaXajUW7VG1rH",
- "DpDNqtAalGZrzyyhVW2lGwD5qK1AA2lRcS8/0yTA4/QRtcs1g9fSt3THsMmMQrOKSFjtjpQ9CcA7NqNi",
- "pZG2F97YvpxXeulU277WqyVBJLK+YXcG0VC5yAuDjmMQRz6wgL4ZLsVZ2jnqnHNt3vnW2IGtLAlfHh6u",
- "hFlX+RgKzcCs2qlPNyBZgEq74pW1q0wd7FkGD/U63xy+aPtomOXwI1TXWJUFYf+/Ofx6+0tvpRrzNGUC",
- "dX7fRQ4oQSx7uJlgq/IEJ+f8Y6SLVxkgPVhOplNd1rn8aD9YZ0yHlt9PAiRFI4NeOg508gw7ffqOJvgu",
- "6b75DrD2//G3vwOqNlaNlrjaqD9UMMwSj5pXyZH0Gac9kmeFBhQtSGGMyZzm6LDPQKiD5Q7a/TPtsy03",
- "9TYw4AfG7gYkNDeIxObuBiBXK47hOm9+z0y9/ccTcmh9oAYuPUXF85at7MuXYdZLRlPXOmF9Stu4tNfJ",
- "i0YmBLhg3drmYUDeOvB5j9/uTQtnVUQCwSQQy70Eh39dr51ew4S3xwt44nsG5eVvJNPk/Ydr4mEzq+h8",
- "/ioq2dDbXEQzqxcZFgmnkMAZXMPgnBjwU1WgCS8+Xjcx4EXRwICw0u8kIoY+Pu858JJPdfeFtRM+fUn2",
- "x2mln5vpe51vXr7cZRiHBAspkfWjckXXD4hnTb23QF9hJkRdaKrXfaOsoMUK3BVQ3e7Xh5q43IyDHvGN",
- "r9zJc2LbmoIViNteFTpWlwmDmcPwrK1vEAl/o7w8fEn4fM5STg3Llq+wJAkt2tqC0JK1x1OOQSlDA87D",
- "JeJtE2Ax4Z/uJ6MoVJxIMSBnoo9osBX7YOxh2VdRhP2BhODHhPIMl3Wq1FWRM3XLtVR22ZHwtcaKOXQG",
- "4nSxEGjqxgm/C65nVHZ9/BZ9FgdNJ9w1yXKAyesXzMvHO2Er7bgaztilF1Dhmc92yr7FNx5lpWCwNF6h",
- "/hzogM5smcJa596VDuvnVpYL2Zf52q1XXgeNcK/3Pc2ll9+pZ2uKSB1S+wklcX2gBiriL0QLmuuZ/ELK",
- "sptlAOB20mNf+ofy6EayW438oytyfjJ6r5V3N11+mqkvbZlYBQoddtu1u8YL6XrGnCNOMwMe6pgLDtEc",
- "74dDcxiqDjThhsjC9OWkP7YGKkYNBFtgDTPXZJJRqF6Om+rtnWfTfg/E+5hBlmjd/8fNiuevSUSfQLUB",
- "1KQ/jfpVDuDBN3ZSvl48Kgs2GsauHOgzKluH/7b9DaskZhzjdQ/Wzs7ELTfMynvPWfeSIcOfefoJeT5j",
- "TWhDJ1QnNIWuwKEQ/5kucQkso3rcAI8FAw/jB9ugaJoY9g28ERi2xjTfNCiK8Pjn3eVvtr/xXpq3shDp",
- "yn7hbF2J0w6iyPupNaBOcLtgl8aFedtYZlQ/a73KuVmN6f4IPsBk1mS+VvZsLg3k5njc7RYgIZd6gp1A",
- "m/ayhD56IuGzjq30mS2/NuHjDL5fLls+gvA5wWsIwKBKZknhZttHDrn45kZF5jjnv7fPrJ2JlbwSmvlK",
- "bDsQlM73gocaHWY3bLnGuSERnWWaQdgBKuoPwqvoT84yEHsg5TBnxg6KoNXhSEJstlM9hQHPJ2uEmvvx",
- "CfkT6bZNQ/s9W35pBW2+LIFnLP2twgb/4BPcyxoXeZZp19eqPuHnz/OMcmHYnXn+HNt4j27YMibsjkKT",
- "A+kQHKsBMaeylX4yPZMLHcJ9lCQyX5JxYQwgE6bQnxb7NpcxICxDJEtZoB6nGauk80YdH4AekKsyUwGa",
- "GLrXkf8w3oedQ+J2LQ83+0n1PBziC2l6OHjQ65r5OHmo2vdgnUzrwqtkjqWbWbdBBm5VxK59/bOLHtzK",
- "G+Ydxgvh9K9j4S7oyjNULCNxw5ZWO7uVNy7pIWdqTu3igl9YyYU1R5fanwdMcJhTdcPSSGCo2+WYAICb",
- "C2vQIuUGQTjgw4qBcyHtYb5eJRHHJcZAZolL7K145LBUr3RnfXP4otnzZGcQGP4pFKXtuidO4teie156",
- "RtidK5uydbZG4eKfo45gLNWj8GrUOQKkyU9xGZ2tpc+4GO2azMXwGJjb7C7PqKBGqiXRiWJM1KKzpBt1",
- "qL5xvb29XxO02TyTmAFFmlJvnkNA5ZbCKCkm71Nlos4B1IbSWq5cSIVqCbh951f89J6ulaE2Xe/hUedo",
- "qqVrdo7+/GOVTaqYX+VGwIair6GvCkHC1pIuIsDUrufCzBo4Cd0W/SoGYvPd/Qem+ATyIJw3v3Sx9Agi",
- "JoChEgu2qP7kYTYbXSqxjwHYU+B1QcyC80h0kOXNdSTQOjNljmGls6RPqQzrCOUhXAM6ciSgmd7BgIRA",
- "nJFFMiv1G5S1UjPI5WtK2Gu842HYixKR8Ulu+doge93zDQLSf4cUDzWHHslWqUSIvA+jAnG5hX/Bx9bO",
- "tR8CNl0PfYTxFTP9E2CgI1JJX32N8RWeYmjlVch1fRWJKzpnV9yw11fQgOsVuaBm9noY22u7VGiBP3O6",
- "zCRNXSpCG9ejNQbp9HUo4UomjFQJg0+scraTs67Oggp/YBDTqDEhRiK001PwJnz7C9n5bux2GXvusSg7",
- "vQ5mr8EcShZoqPr0AJgoY7qeDXpkhQsOOptUlU+f+1C1XBynd84v7RK7y/zUiYSEgZXl7nxvZHIqi02x",
- "YtCVdSVht695WrYFtiqtFf1cIJ4aPjnGrHXIK8O8i1qKORQGtZ7gV+QdvesfT9nrw7jlGNgp7yIjPRdA",
- "Ksc9BWRN1J06DHcv59yct9MZgSC2ZliB8KHGYGqXcwgjcGogeQ2c+Uxgx3vSIqHWEqOw7HHhFREZCSib",
- "nRQK/iDoLZ+iOjZmMw6md7PkatHS3rEnzdZjm+TESeX2eYzd9t+rAmUjiPb2Da92e9647agsNSAS+8I4",
- "dI31oFukNn3QEzElOBJxtU913CNxtYu208riaqPswBEe7T4SOpeGFGJC5zzjVGG4S2MZSFw2vna3nTVW",
- "dbUzOGbWrrcGb8voXF6VPamfLlTd0JC7KWDtKP0A/1yNYY5rJ1WHHazy5c6c0+CvaIrmBIJ+MVP9MaTs",
- "w8zvU2hKwiy958uS/IDcAfWFvuqCpOyWJ2zzxTjlph+qZZuvxTOhmTKa0EpxsVwQB2z22lV4H/QIxTpq",
- "ezp84w4dCSUXeDYdmDGku0LVNjwRQz7iFJDNyE9yHCopkhnlAgpYJAlwLu4V+1wFwhmOL1aA2sFLyLdb",
- "hoXN8WpRBIbEoQIeYu/ZsnYTCRmJEoMOtN6Mi5sAN6FzlvAJT0jloVtudWc/UPkDsHZlYD4hKdPO9o9E",
- "jA3VeBoTJ1BALmJ7Ln4LMA+WkK9CjxxoARtHwjUCQgvWNbEJpMBaDF8HQC3H9PVMmkjEFWxeqCOqo/MG",
- "oRl8H+j8Q6xeDMB6PF0e2vy6/HnSjWlhZIyN+FKJ+QuuNnLemPp1nKa+R83TaPvlAF/I2+xG3+BuDlCC",
- "DuPyK4dqEOC/7y9nPkMiQUhb2/xWqCnWvkXHqgYCa/7KATlQEnprA9qQVEtXUmaoSCk8WwIQegEXyptX",
- "hdysGPfhpG1XUubM0JQaCnyLGovryYjoRFYa2BumR6BITPdKmH09iMSFDxH5ujSqGHl/+ofTy0qRuANj",
- "8eVlr8piH/utSIQ4E1SlemAlvl5qVSv5qq2zTSn5Hh66Rlo8oVpSGWebagIPPSxw+DgsCBFEt9mO/S6O",
- "rzXpBp5YjUPXWas9jIgJp3CJhq11LT9FNXcfisdQirukSiYStcwNdP1B7/Px6VX/+5N3YFmGYkGU3phB",
- "kzOluTbacRQUtPJ8xpQdtuWKqK0wRHGqfBgJ14PATznEsWdQFE6u7HGwXM9TtKrWEf0jYc05rknKJkzh",
- "mSIU0qeV76L/ilxcvsBdcMp34RAU8bxF4papMTV8DjFdsWwPZFZ48EmjmZVxvtwlE1baesKQs/9r3CZX",
- "BlyNED0tjzLpuuPE0j61mq82m05z2x2yNbx64eOh2ZIoNpehC5gfnYwzOa5F60uN0cedQK8HdVjZ08KE",
- "x3dygiMtU/YdYFRQuwdeqyRvf08gH+vDe/Lm9Pz0+pRcnV4DbDbUO5dtyZRcaA++5kZQ7Fa6eJUDs+H2",
- "lPZROxmWrTsmGeJLUewY4AkOodmyrKAQhmeEhlbHkVCs79Xu9hS+1UP89Jl8eyZAPQ7DhpS+tftn83Xz",
- "6GbwRqYf0gRaF+mdXHz2xEGWwTNIEdDQKc99AeMNLnymplRw7WBE/JsAG8kYXljrsVw4ClRXuhdpw3Ii",
- "J/gFmqbYXtUyZ6NRkyrLmmDQ0WDSRcLPz0Urcp7cYE+/iiZq78dCs9B0FdJfh87ideDdAZMtrBHrjRH9",
- "7er43Xk/V9KwBFodq6lP1XH4YwiwNLQ/DH8GP9UnHOAggMdYIpU3tOtlVbYcRAXi1YpT1A2CqAruSTyR",
- "4yXhaZvaCOfv2G/+A/XG1dYbJUvtBB6FEsFN5iF437RcTxve9/pdeozl4XLiOVmT7gv0MX5FDgeD97CZ",
- "B59P/rhr9mmrhoI19hMybGAblICfYQYn0DpYSIOAfE5APrLyX2k+FXb3tmwbEaTzL00sBx/eDoXtCIJX",
- "k7E9IlUKLbnGy2rrNCsq8kLb+xnQF0gD+EJd0EKD37ywGj1aHtjiGgAZSkyc2BEXnF6+jrlm2zpbl04m",
- "POOoC/UjUUJeQp8O0oUSylL4HmCn4hKOsbLOSGjG7IXh+n4A2N5Ywn1g1+9uIcRdci0gsIlYJGrz1Q41",
- "xBloM240iX0BRFVSx9g+12Xp+3tFKhI3iHWE6abCTqNHEK8LFDNZkmtkuSKGrXDRMvizR6uxBlnDfTTn",
- "IOjx0+4OMsucJzSDMRuuoie+Y8jH3DLKt4eHjh0xf8V5R7rfkpxOQQ+ekBeHhwcDck4VoBpWuMH3ElcM",
- "IboQBwYjtnaukZjwzDBAX5UKOJBQMrdXenDfOvptvPMANHJbvvgH3wY4oZr1uSi7v+li7Nv5wnSg1KrI",
- "EDB/0JL6/ZeNgfpe6+iexYCvAAIKTHIou0A9nxjpGuNpZnolYyNnYWc86BM/ZtBPtzU73b2330QvvXt7",
- "sSYENDOviGtpiNkhC+6xUjaMD/NuTJJ3ASippk+RK7/e1XFf9aUN6nJX3UU5vryP4hI0WTv//9ZTfoV6",
- "yqpznLNfrJ4y9M0Ah2XPxhYtJQeoclO2cHSQNw6yd2MXx9BAFKONCI3ITaXH4lFzW8VePde3uYvigA2q",
- "dz7XiD/vO00uI1FvtOgq6W+Z0hCnuFv2CBcAeNaD7FmekLOLA9A7hBQIM3a8MjM7zIeL67MP74/Pj9pa",
- "dlo5HvotYtiyhGkUS987csWIxho9dCYReit5iqn2Ap1BUUdI92bUwbhLruQ4Y/My8bps/uibzcPtbsnQ",
- "ki9Tb+n5hLGH+kAbYYTWuMox6WMkUIVB6txsdS53fldHr5xVpH6jF7I8Ucr3UGwP31+yvoMwRLW4FkZ+",
- "jeHa0rPxTK9OjRr0p/jEjtXmql3ULm6ZZ1rouGqZxDFUD4rhIlFn3YMBOUvZPJd2twfkshB6HXYVMCko",
- "JDxEovJ5zNICLNxKFI0YBL+GoHO9q+9q0YejmuMT/Rl4cbU5ZyPwiHuEyLIj5heMhl2y0KsZyujWGMcr",
- "75UwzwqXfLw838rSShZ5u+l6jAB+1nRD/oXnX4E7blpkVKFxpRkrw134DFwky0iUjQW6qxmCzzSJOgC0",
- "YH+GtwAcDdADrWnsTdmD1mgqzv4p46h2hG0RVHjo0VK7QMMo+2DqqgaBf6gGOhsDb/axpw252RG+VLAN",
- "Vte6Dcl/AcAI3ARCq+1SW0q1A8usHfq94CLKnpwuyI2pHmWmlUdM8cGyALIPg22ILwVe/SfFiNhji3qt",
- "yEstVDr8TIfqV0Lz75nZl+Ab/Up/KL909iZ4ix4NuqMJZeMpRXdlhC9Uf9PKZR5ZcfrL5rYvIeuRNI8h",
- "64dOiG+E6IAtck11n1zg4Djb1Ct86vNCWzxMECEWRqWz+S9fKDWqk8dpWtmnJ0wRLgd5aLGqYxboFEW6",
- "PBi5B//UID7HaerhqMD/+GiyYviz/ejZ5vKQS8ixWuWUHXcKE7S+0F6tWNx2Jp6OgOv8Cz+4ayEeAGk8",
- "e0PAO2BX0zIObuq9Xcs/yfHmW+R39oFm//ZKJCn0xlqPIZVdfx3KLvShdq0FN7f9bR5rLVq143vQRKP2",
- "oqv+6By9ODzsdeb0js/tnL+Ff3GB/3qx3v30SVGififH267S38nxLybTu155pH1JExkSaBCBAdvqQStz",
- "NOtiq9qTsZUjL8rWa0+2AW6MbZtwESqkHrQRh9tfOnP56T5a1gio6r2MLFj1urmmY7PT6SKUgzyd28mN",
- "8YUcT6H55dYaoocmeT9tiPQ41Og5vCauax2dfKEBZCfrh6SSP5BFL4P/GxLJdy04KnsvzaiefRoCMkZf",
- "G5lDnGZrzNW+dV/9eaVBIVVpn45DXDWpFVnlPGcZF8ynHrE7JEUkuhgFwlTv9ICEhuffvHxZhgD9LkLb",
- "s4RmWClp/y/0rNZuqFtO4ZWT8zNw30EvHiFrQAthOkZGwlKLdH1jpZPzs2eQuUUSKhKWDU+MyvonLk9p",
- "IV0XDt0jY2lmZMy06bPJRCpzFAlCXgyIa6s79Hj5tRrUr9bqS7UrW+TQU48QzJuiijko2krbDWwn4GIL",
- "YQ3YeSy8bCC0CFWqczawf36JMVmHeMBF36N4I8F8ZXwXi1wOoCYW1p6xtOe+i013CzHOZOJK1aGDB8Dw",
- "Y8evMYNWiZbmkyw0uIO3/fa5a6/sYeR6IWTwi4tN45HsJ3Lu0vWwf+hQL+djmbkytw/X0ACRpfixrmus",
- "jH5Y3ENcQ+iN6VL2aK3F4lIkQ9dEIBLylqmF4g6ZoxEf9q09X1dG5tBZ7Cn7B4SRNl2vb8Nx98jsn7Mc",
- "4UtW3VRWToXl6WobilUpc29x6ovWt+a7emnnY9m+yG1Avjn8pl2MRaI7o9pKp1BQQ5RcYLtwUq+Xdm3U",
- "s8Ja+ygDKrhxEEOkGtv7QaWBi65f+YY+//jb34kPQ7ekTbirvVom/XQ1m5iWts7TNUr82mproE8ThILC",
- "KmpVvjszZe+pLu9mMO2raodFN41nGuSjXcBMpiTliiWhq2+Vm3M6Za63rs/5QEhjx4J5oWchccjnTvje",
- "LdAuFa6+WtT/GS2MfIYwtR5y0wC4oSxzBaDDOdSFEdJFwL+VtKWhz8RyOR0Ie3txfO2gXgjijh7ZrRrZ",
- "Tx0MyNnE2Ql4OKCkTPeqSVm1TnzQDlhCGzVsp0CX2p5PLkgspGEx9N6N3SNxqHiFIGIKDc3TIrNfZbgF",
- "gM6L9ba3FFr8duHtkf/TyLWljHtEuoTcAyTjCg09wPUznIKDbsC6clkmwcA2v6r2cU/tnZm2bU34bC8s",
- "XE4mcHkjHwEpFtQ3gA48UVGWSFrmfGhIHwO5iT3tkMq5YrdcFjoLELlbpGk7oHtdsF0tRfK0cadynC+F",
- "8r4+j7ZkIB+PgrPuOwfCmP9kCbtnAirGYaEjFGqPKfhD00UyA/i2NUHv4TatZNDIgvtpI4jTvm7XNdvn",
- "0BTUvtjiF73X7VE0wkhmS3L+4eT4vMTt6dZUmpwxdeA6fhPFqNZ8KliKJTTBEgwvh37hmTVSxkuAsZmK",
- "Su9Waxw259vhtx0NPjhg+ydp4ueGgjG+0Cnf4KXxp9orGf/MESG/FZgsDFjjEIhET4E/fS0hjd2Onrsb",
- "P7dT5bREssIG6DVfwk9y7CGP2gCxtrlR7DlF2yW4E5o8K141qPhWDgbkDUuLnGF5W64hISqHezoSZYKs",
- "cHiLvv6/Yqv9JMegNLyXag6JuKXfyC4tZQm0bOQiUWzOhKEZudVQ01RP4I1Et/oMrDYAebF0pGfUYV4l",
- "UlnryQoSoxgbvOGTSSQA3Yul+hV+27eo6sP7PZJTZTjN+lYPLKB8LJG3TC17kZBqrSM0ZgwfDMgF1Rpb",
- "N7jeWEYicK3dzCLLIuGpulrjjX9NFZ84VB6dQ4kJWoU+CdmBgGoSl2AMtRXbO2ampEAVynmNBBSsAZG/",
- "cq45iv3clNE+EAh96onO0CXTIGW566vu7JeN99EfSxRfP+HaNL33C/1eWAsfCYdIZRmmMnNS+s6IKgQC",
- "fyE5SXDjdBXrw674RPQJz1iPLHjONMkVt9ZyzaM0VGyih1DGx0Yz6Ol/4Eofpd9tJE3YCtyd9qIxO6Pm",
- "KNqEZpqFaNlYSkvrxmjZY/aiBNI4aZJu8ii5RwMimGttgl7y0Bz0P/6TpHD4D/5reJveuRx/oljf26/t",
- "Tu69bxfMJ90lpneFTz51stJZulseOE/16r3izFojf035S9DHo0xDb9Pew9oemh/xpDp6C9Z7tiSnf7o+",
- "vXxf09Nda6BVXX1Ol1CYiwu2593+LyQ60wCwMqwrWL7zVItuDqzrFn4tnzL5E0ZyQzw0x+oKKfBfJrsK",
- "1tvI/w9ItmqWd8OfpyhrNiZcfRS6wjhvlZzvnkbv3v1lJFxhLxtPzn/87T+RjFgU9EuVJ737ZHa5bb13",
- "ytUquzj/YZ+LidwJeQRrwrJlH+qioWGPD8x8vDxH9X/GyA/vjk8IBlegWW2N7Vvj0iBJgwBF+RmJUgmP",
- "QYSi1ZDwnBpo1LZW/RnMrL4lXsXW8vFq1C0yPmHJMskYzFpI/6EAmzGjIs3Ane6k7+E3AJu4kCQFiyvB",
- "dkO6B/1awAYruAaqAOQH4OxyxY5Ilx64vm3UzEARjomHmFJMy+wWS75FWH8kKCTWYCV0d3xQ0wYwqQIQ",
- "3YKLlpwAliNiuEUCQNwMTJXOx3xaWHIBNgQo1CQG2JUVhogdChc0QpBiwtUcx2IiwV4h1uBg1NSDvVU2",
- "AjJRHYmoU7vEehUSQ+Ni79SLOptjZi6ydmZZ9OlrPO0wm7Qz9xhJpFQpF9Q8HH3hiVvF89DCyXMP2HZC",
- "OjbqkQ+XLcwViZo7o3oSARK8vqMOK+1gEIk3VaYbL0kyY4jAtonrLBs8ml3xx4pU+sqJIjCIMVTjA2ia",
- "GbjxPlucsFEY249uLKI7Dh1MB+SNknndNgAUPm40cVZ3j1izuwfWOUGruxcJwG/3LhU9IG8YIh3wW0aY",
- "kMV0hhgNVhFhyuMRVds6I/IrtK0CQVLiY3DTXptXTenbsToPuG0s0+UvWiN8cGZaqO7zGwkx1CyDvXSe",
- "HAIB7u0e1vaqv1b6H37GnMbPmW3wwF35nhlSQSZHXHw45rsIiaZxy0c8pX6wH9yQNFA97yHNxCEmIN7b",
- "THEBQV1kFPDmofyNRJfdQTLLKKfGrlP3yJzejcAJp/lf2cErd8gr53jMCLb3lpHQPEPY25T1PZK7V9K2",
- "BYKfNPp7n8zd/44JPY6z74Gn6sIyepmt6Hn6nqEjuDCHleTIhvDRvidxY+toSmJVYIsPb+PMaU7kxKNl",
- "ZMu+g2tyvOYu3kh0Y/zB+b/jA+92R7Q7OM52igVcBSnLDK2GOICtY2ihsuA5qyV8Mg9w62XAgNhTB4CM",
- "Ln2l6cBChuV37Om685UDVI7qUx7N6oDb2yfJnInPms35WfLxReUmcAvlOgQYXIpyCAlVJdVnkwg7Kvew",
- "m0x9FPSW8qzBlfYhZy6Tq77gigTxP+0iQTCd+alECEzWGffrndnKZp7xz1EnJIdXuiTzCaGR8Fu6oJrc",
- "cMgfJzFEvOAJYTUW+xvuM8YzT87PAE9Uuxx4LrBnQx+ikEVOpCCMqgyKNAxgyU8pRpIN5MqBbF4AFh7g",
- "hUZCFYJgnrpVRgASU6qgTSA6vJVtL/ozWShyfX3eKoBOkOpPLRVwmI1t+JDovqkzZnP9atRVnD1yly9D",
- "WBEDNR/t/Y6I1R31U52QKyZSe8WOQUeQEzRcXU9bTRD8CYFPPQK8CPfxIBLvsHKSfHsIbwJOPTA+uPKe",
- "P78yitG5/YBgU2kQfPb58yOimUhJjH1djkiV0e76IrXMFoNCrFjC+K1rRZFxwfopg3JOayDDx+2s4zMX",
- "uweIwNNbaEKIUJ5WDYBuULcArAU4BIL1XL9eEs8YVWbMqIldYP3FIdEHA/JHBwKILj3sJQtxY+y93zRz",
- "mPVBExBzJDI2pcnS9Zbr/+7qw3s36beWbP6MxCWML534ZGDYm0j4ylndeqzhU9syF+JmWuuQK43wl5ay",
- "LA3rcERspLOnKSTPQELAEYnX6FJJK0Bilq4cpGVjCfGaBOp1mubfilH7RAqW27QvYgutcw2IpUayWEre",
- "Ucs3MA3cVvi/IMTevwFmdGep4ahYuQW9uDpHnZ+jDvwYdY6iDhq1hipjL81e1EGxAL+p/gv4E4QB7B/m",
- "lIvBVMIf4UXMa+kcvehFHeBwsI+jztHLw0+RWB8IslvcQI1fxfQX+8WXjR9AB9yOX+hFHXh+NLf//vab",
- "5jmlUrB7TSgIHXjQaPjjy8OXv+kfftN/+a/XL/716OW3R4eH/2/UWX0VaRVGBqk7onCCQHd5eRiGHrkM",
- "86hz9PU3/xoeDkVVIwA/tr8e2vXh7bY7D9bEwAb/d+ioiYyGnEe6LnnogGBb6iDLkSEjAUvWpBvy/JzR",
- "JqEBEBfYGnrjDXLg/Nq/3BCBj3EKacgESuk/XBI8R5W/DYPpOecakiK/kPHw1LnsYHwQX4oB8L7fX3wk",
- "mqcsoYqMC710+Ov2f3skvmRGLfvH9q6Mwy3tmgy4LBBdTKdMW55ZUG5I19WZOEzKSpP4yrfqi1kDgfi0",
- "kl5QjOfcrGpRmnTn9I58e3h/xU9wPXs8za9RY4AhnvSmtCN82asSZ7DdORGKc3+9MqMQN0IuxC9HYjzQ",
- "3XACW7LibH+Qx8Hh1bRlXIBwoTU3Dph2RyEXYc7TvrXFc3f9+f7q+YxqFvdIjLdsyjXk2LJ0GC7cIVy4",
- "9pn6BR33IhEzyDdPK3Vw0JLd21oo9qDkf3VqkajV7qGLtOxCE4rzC+Gjx7gWqHGDXiPximbgJoozWJkr",
- "1BJWYqCRcNW+M66xzyxkTxyBVwWpDYoLTzMWdT7FrebLlUcSelp54NWWLQgvuLfOEgbDzy7g4Is0LT8H",
- "FHQ/p5VW8aoQcFFmVANcP8Ir2T83n5CHxc02nC/NqEpmT+WpOMXkd4cYYdlMwCIhr5XmuZJ3fE4NI4JR",
- "xbTpC8ans7EsFMGJhQ4HK+XAyUzJOZv3pxKKPlhiBxwQrC2Euq1I2Cn1EdAIcfrjORcjnUgFJ96uX8dW",
- "VeWGZZDYkSs24Xf9D5f90MImEiCID3okdlFC+844o8kNvqPpvKx5OXDnP6NiWtCpffYf//GfAAUhyJyp",
- "KSjBRlo7rQ9em5DmmxJFra1kJzpm2uA3CUwXu6aXsy+RJADpox/aSf3jb3/3lcFOUyfx4eBlTLpY56JY",
- "xm6pSBiZZBJc29TBdYQGfiGWqWROqKUCtdcWNYWiWd8vDLaTMwcUsphJzXDWKHdw2lbf//Ph4OW3PXI4",
- "+PrbHw9wsuzOigJupxbDjF0lHXhyDJbsjuUtIz+8v/ojTnTlRUDut8fLvg1JGLgcgE6JDwfffIXFHHYL",
- "E7fARKasjwkfjrcgNJzxsQLnsn3+RKbskoobYNv+v//2AOgOnDsyfM5Gc43lO/a4Y7rYCygOmtOM5BlN",
- "GotUrtxmXeFRe6JM49ogX0h1W53EBlld43/Im8FXnUNZ//KrOX6xFtlpSFqqGGW3LDFwIuy5nHNtrXu4",
- "gapmWiS6FXuKOMtMM7PV7lrVzUEbsucDzLfgDXDuHLD27IBNuIDtFptnkS4u5sCd48qN6f6wUaPEZ4Yp",
- "s6YatFV7KmsNj8GbykBPc/bLEb7Qua9OYAOisC8MrZL+n/CY17OjZN/Ifrlie727Wwgc6ffi3UeOLjVx",
- "rQ9LPAW/2m9/0XuqOoEd+NWF18zsn59dLWWgDKDSxPEhUjZ0cddPnXEELZlc63btWqHFeNJigv2loXU2",
- "FYSnTBg+4YDbfMPEIBKx46sYsa3s/0I6ULYkbJ4bNFxiJtIRVKa/fo11yvAvp+O7vjlAMcHznBlNYBYL",
- "17MTuNvXCANPKdZXjKbWGogEKj6vnMc89PqcyCyTC1Lk6BoNehISGPH1EOkJy4YDOlKzKopMHzblqRAp",
- "3ABf6HxXxt9UXxyo8M9/qgGvxK/XhYvhbNzvWLvE+ae9gq7cIE9kMMHXv6y5VJvCDheRJ/s/O79eVc10",
- "qzFZVYl00T0zDDfTwb7M6wf4eVvy/5V78umzo/1ITREO/9OvJrfKBznkLVPYq9zI3F5IUGKTIM6pK7kB",
- "Z7U+eIoygQ0sUEEz31a+iYlFZast8DPNqK7lgxJqDE1mEPZcCOgkHomMixuPkVJFJqx3INUzuSBRp6zM",
- "ijokmfHcIcdCOwTIdc44Rgh+Kua5jxSU00qZoTyD74Ob8BTUFeh63AC2I54ZqAcFWCJRXd6SGdRjGCYA",
- "WLOdVspqPObiLadlQVrougo90scMHKa4fHAu+OKcaiMzqCodMyZg6pZ2bY0GfUFjuWdPfx7DYOdcm/a+",
- "OLCUX9HJBGyJkvmRmS3dKLQariQ4P+153BLI82fP+bA9YOkRuWVKcyl6ZRlspTiPAN5Rz/K7ZV08P1lG",
- "57TvPuSdXIDt4wuxuzG8N8okTVkaH/SIKKA5ipxYbXwNnx99++GZSiWDR6MJ0c6f5LgN2fbpA2Y4wsbY",
- "OYJfuzjZY7TPvEI6DwOlHb52t5bBvSLtx6x+X/teqdu4A9LdhFFLSHfD2Lnrx6xIN8lkkU4yqliPiKkC",
- "INVrax25dN/wZEIV9BAHVFac7ytsw4/Afwp6c7MUqrOLMtpNhiTqJHKOiFBSNBdk2xN37Rb0hJuNQ5xQ",
- "QzM5bYmK+uW6Zx6pWarDsfXk1L7Qh/vN39YF1/1xOOaCQlf+bU3S3fkmUELrx32mCZ1azQI+s6zuf+oZ",
- "gHAdCdeamUgn8FA09OB+ssrBMMgY10s91IE7IZJQEQkutKFZNiywQRw3JQjxxzPS9c3MrWRBsBoGFZH2",
- "9zcyubHSic/pFHC9XHKAIe6jDg/O/sV9p1fv3Qs6g46Eq8l2r8F/oTJZCk26WH8OQVYoE9vMnN954j85",
- "j8JIy7Zr9YKpfjiZbisdGz0Cwx5bDunXPguyw4+4L6sOf/Zvfhq6XWjvRv5GLgRm5sO9RA3TUI5mRUmN",
- "dQNCoeciVLqkWg4iAWAfpQwC3c69h4/P7ZegNTiEfCLRPTn70+j64/v3p+ej787ej94dvz/+/vQNYAAe",
- "OEm34JpVADv+rTnPAxZY3cXOLsX+FeK2F/z7nPHy1NoP2FPbmh7+Bbn0zB/UV4FoCAi4eBSe/Uylb981",
- "sU0acCGCuvm0s/DHwh8g4jqLrdT8rz5F2yV/VfgePORIo3BvP9GXrJ/ueKit4ZtnNIFynPJoRyKR+RIS",
- "Vow1x+xPHhh+YphaUIXxU1WIwGLugkLgn0isCIMNp729Cv2/D3UoRv/vI/14R9ppR40nOrTWbTvH7hJ0",
- "Z+p+pxrNxN0guuypglRzdwDxXdLFi3Roxx3OpDb2BHhbIpFCYEYFRJAstQX4QEIpmFX+YvhxpJmJnTVR",
- "KrFSMIALwmL3FmPRafe4mKe3InCcppJPl7boyPpl+xh+z0xdLe57FqltoG8d0MQxLfjxF8gKrm0YsoHV",
- "yPl8zlJODbMqmCUy04SbI1S1wAxE0GIIwuEoPXf68FeZ2xd6CEniPRaBqYbIQ4q5zwA60Ic5N46BALD5",
- "hrG8Dl8tBXuFJZlUuCili9gaiQDH2+R+hbEeP8BSHQIH/dzxFZyBc7g0QQDAVq4IfgzDuk0Ncv/w8zWF",
- "eJzGF49z1JysbjpXCL6U59mScLOrWHYsXtWsVgG94QHcuc4X5A03kSa14NegD7yXvrodSf/ZVACv0DZe",
- "/VVttzY9oouxCyLuykprnuSWy/Pp/a1bxcyK39G7RmVZNIfJwzOZpUwdPIrDo05dHFELmuuZ3Pm0Wv2r",
- "3Qg60xr7QXx/eu11NnzzmXa4pw5NMB7OGM3MLH7lJCxcNpFgUBqB+QguTIUUYukUUUaVLAzzNTIz5UD3",
- "/DgR+kuCL891VbTXCqZo943ieQ8caj8V2rgOXIJpjQiLTffjNdOfTfzYsdrbIdlf3XVEuvLmNaCXoK1X",
- "iBDGOPi1CaIan57aTZJ9q8Q4lZrfcrMkoPqv7/g2zvWt3YZTbmbF2OFl7tqo6Bk6ggF4inRf/IbM2J1V",
- "2ZQ+eHJU9As8ML6lBrJyYWaQKb3MqdY+ohz/qf9DMe5f8SkUZbD+y29/U5bRAkDdGBGF+1c/HL/89je+",
- "9sidOwCKJDdsibUmoLOWhTWVFh71po/xgLxzVYksJdqPriPhGyEdvnhlNVFfzRgjbG8FDXhAPghCCao5",
- "cV7oWYxox7DBiiZQ/qKoSGZVvzsrW8+sNp2JRDddbf0yLpQ2Ht2YM439ch1+aZxD57vyV1988vLwEBPs",
- "hIQYlm+uS7TEeCIgnxIH8uva8WVygUHV5t4kAILyPXCig1fdhvNR27VbDyUi02XP8mKfiUSmLHWZgDP6",
- "8tvfvHZFS4M2nI4GbtmpG//6dxwMNSIHbGHy+xoUNE05Zl5eKEtOA3EhPFVuGESI+dy2hNvAY4fZ0BjC",
- "AKNMESH7Mg/w2lbSPmYHlR0m8sYje3uECdINTVQqPVS45WA+ndWA6J/2NkCcc8+L9TLnz1GF/VGEaDEk",
- "xID8fqi1xJJCcfN/2Lu63bZxLPwqhG9qYyTF6TYLbIpepEnaKTbtZJN0blaDmrZoh2uK9Iq0HaHo7QJ7",
- "v8A8wT5An2Hu+xDzJAueQ1KSI7tJ47TNYi7jSKJEHh6e3+8rO/t//2WFh8+BIDndcw14vYtWUoTKelOm",
- "vAXc8Q6VTBxDyrrUhuWR9WnssYCY0gQz+fGSZyz1pAULrvmQC3swe87QEYCnE82YrteVuH5je7BQWSJi",
- "25r849cp62nU82wEKg/TIyBO/E39bkiwUyFqU1sTiNqPEMpq9aQPYSXCSPcU5FkZ5VaFtLvbX+TNC+uE",
- "864G8+abDpUcC343pMhtiBCuDEKwVWK0TopaFcvOe55thFk/Y7laOKrmSr0A2V/4812oFawVAVqjEavR",
- "MS/Ga0rE1d7YJ2dQbfjTG3J0fHJ8cUwOD84PD46On7oKSZmxQpT2CVWJVpM+yNVsKRlnXE+RyEKn0o4A",
- "5SCFHaOLn0cMdDH7JuPVUkdXQZpKcMAypq1o99bDuDd33g2B3B8ayXhAZP+sgK3HW98wUf2vrCEe2vS/",
- "ZKYC6rrBEmxmRwwb8NUR6b49eXUUCz5lPqcQEltDT4IdbljnHfPsiznh23IW932WrYzyjZpCNkqqx01f",
- "fn2JfVCHn8tbVGeKryS+/fkXDoCNpIjhjU791V9DRNxgNzdtvd9zJxP3Gyk7sImDMRGKrwm2G2BP2zZ1",
- "4PaUWnv4XGpWGE0o6Va2Es8i/4nv7LA9a0xBXWAqB9dNqkGzxwRif967hzQxWD9D6/GlcoBZgGePXEvH",
- "o0FCjuYog1Uc7En/L82HcqOZGEOpwlwaNYfwn/UCa14f2FPg0AcTrwbLo9s9QDkNFIz3rdlrg31rD8W9",
- "RtVF0rZhT0Ck/9Dta/SAnCI/nquDCJIa0kF3cHdWubY2uT8Vs9TntnDblopSya0iA3I9JYn1UKIGlZGT",
- "PPRhVtuo7JaGEt7VjUiFqHZqawUIdGjVaCxv56q8dQ1eD+38QGe1xh7lCvcbvmc3cL0FpzCsW+/Gh8rd",
- "j43oBimqreWkNuyGCh6uNcK4iu/mKA/HVGoCOOxLRezcCIE5/tjBhiHigZvXfZIxqRnpOlA3MlKaS9YD",
- "sdczWtj/nf/thBtGXlyc75Hnrx/vpRLyIw7mcGx0LyGuhwA5Yi8ZjO5A1QSUddntMZ5rlqXS+vZnbMSt",
- "iqKCnFE5JS/mCP8/ffbnPmaNDkaF0rqyOqgknz7GQ8EA/mtEZcYzQIgHuLPu4NNH8tuvZJg/3nsnVZGn",
- "8gfS3Y0/fezZn+Er4fcBZnA+fXzWT/YiMlTmEqPiQpOcyzinV6m0F1JhNw20KsD89jwCfsEExazqZcH0",
- "pRJZKruD6oV+//d/EY/tt19JP3ky6AGeW+1LoAEQGV+lSmWAlXDcnoJdcTsvdpIFddgTYZkTcjovWAwf",
- "lMoxlbFd7OAh2uveeEg/hzxlDYwJLTKBYIippEOtxNww4AalQJepVV2XFWpuuGSi9ERdWSp54RDsDMEg",
- "DzVEKq5ZLNgCKpSs5BDNcy5owU2JFQcoMBMoSeVXvv1xWDpQDkCcM0QwqpHKzCVMzRLIvXBdjALOL5Iz",
- "KrmcjOeCjAsKBo6/3k54YEN1QHjQiIt8ApIM51zguFCdUKghl4A2UghGF1xO9lNpBTbeReWEgXs9LxZ8",
- "UT/pHIsRlSXId/w4IsyMkiiVIzqbocCEnaAVfFOmci79xFnRfWSIoVOGg6RSC2USciCWtHQtcdbIkwqK",
- "LybwwqRg9gsy8g81BDLLjA3VXLaj3gV9HGDv2pQkiFOlu/65UXHlXJ4wOTGXnf3daG3icuWRRs2CvdzI",
- "WjqAxM7+bj/q5EiJ0dnfs39wiX9Uo1SgZBuGwSVvH+RxfZDH/RuM0tS0LwDgUElS0OV1MU/IIYrbkAm1",
- "xEMNMDDtrrcC4SVmMrHbEMEyHe+D1Q/YqlbmOTMFHzlw3IYQIRSDB5XUCjP9AV0z7NtUItBnxdYLbgXo",
- "0RhED/Yr7kAfu4J/+DsRLge6xAtmB2eZ4/fq14OzY1WksobU44YIL7xkbOY2OlD7CiUnsaFcAD2JNZK6",
- "LJkkJO3UEm+hrtEZLPBL2iEUzwGaypxfsSzOVE6B6idEwCqijBXBCKid7XLRT55EnbFV9aaz3xkLRU2n",
- "Jim7NTnpBznBHuR7bp1Y2cCbsbhBOr46dON2DMMfy2HBMzgkfkBLxEm7X3Uh3GnD5RfFGLYQRdhkogGF",
- "/c2iU+d47T1KzUtkXP9cSAouIzxbzR1xTVzO2ajvm8t2ayEtOwGLwGWv6xLWnI7vPqR10VhKtZSsIDkt",
- "nZkJATrk6zeXrHQ0VcQoqBpD7rSclq7owDPAwQ0J+bmqQFBSYBmCbwN3zj9UbTWkyfXXcCGgEkbrGKo+",
- "nUGNJGytKGn2BcK8XSgQ1vuCobJjuSFuFZtq8czPUVQa9GX/h8yq29h5MFWNrQbiWe3DL4gcoSLeeT9B",
- "FbgSOlqNweiGkL0oVF6J2edDMPphLfW2IjgLNW2s2u//+g9qFNQZXdQ5qkB10vtuVOY1c/7nIGjrx3By",
- "dHtDAavtP1sWtkL1oKZp58OgAo2qUC8cab0LwVjngEuym0okvagYOff6f3JEe80nzyW+UYmEY4xqa1Tv",
- "p50kScKYWNNx9JzMAHKVcqET4qqinSc6OKib5QOPT+1nZ00P5Y84G/do8+AImw1kmEuuiZuJbYOB3+YV",
- "wnI4D+jo+Uo/wYaixhPfPwHwPb6CsRXXp/mU950howUr7BLah1orAiWsbQee05zFquATLgFCSMUZM+AK",
- "1uBWzk5ARkMFkZ4xeJN5ITr7nR3Al3Rvda3OGiYAA4wODcS+tm70uQ/tebMmDksEH7NRORKMdA/P3h71",
- "GndisOH6zYhrGNUAsKMKljMCTFgM9q+gvFYPd39ff/TFZcFYDHQ2FQzVrFBGjQDk0+stTyly/QkHp69I",
- "pkbznEnjO2fdXZkatX4OktroiAg14XJHqImam4jMqNZLVWSOgT8KrCdzXa8ot6dQ23sELn/EwKt62mu3",
- "2mta7oWeJOwcwrMCDoRYj9SMZcR+4ZSVGrkeTl7tnB/91Y5Re+6Mx/aKlkdXp5MzYl1VL3iG3CgIa9sH",
- "r8QhmiuZpLJWYOuNe7BmsWL7GuExKGCkGsGyG5CQVOYq4+OyCeKXkNOzXYL5ISuVYCs/rV6xdHCFdjKj",
- "VPpumShwtJulirWhk+ACh34UATkoCbDQ1kyVJpUFE4xqFshtasHbMcMKb+zmQM3s5rh2Em86F/U+HuKh",
- "uVszAyPZSdEJOb5CtLt6cD5L5UoyLHhP3veIyKSwCwKkzSGjBhjKO4FyBpyFhKCTChNpv76W3AbjMcjp",
- "U2iB23H+G9epxEu93I0BpHkyF7TAt/eM9mi1zPho6tbZYUizxoThc1smy0ngKSs0RMAO4L3JhZoyqe1I",
- "vsGnbWUgfjYSSqKi4AtqmA+qy4x0PSG+KHvEg+HZS73QJOQckAtSyeSoKGeGZTE1MYb8OSUHx+fxy8PX",
- "GICfCcqlYVcQCvfhfMKu6MiIMpVKjiAFevrT+QVmIJpYCuaSFQxwUZoTA601MfTIt83Payc5DobNtQfi",
- "qRMrYIAxSP6i5mYIEW7XMAlhwwlfMO2bf+DwpPW+xuUlFwAApq0gDdkllxl5c3CRkMMAe+KGtj6t3ZNS",
- "LZ8iJBkiEWIBKiaHRa1f0z6eO3QKOB9gnt15aKVpXUfB27MT3Zgi3yX34ZcP/wsAAP//",
+ "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",
+ "HQUfzk5MZYl8l9zHHz7+fwAAAP//",
}
// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
diff --git a/server/internal/httpapi/router.go b/server/internal/httpapi/router.go
index 59fad07..daa5e80 100644
--- a/server/internal/httpapi/router.go
+++ b/server/internal/httpapi/router.go
@@ -190,16 +190,12 @@ func NewRouter(d Deps) http.Handler {
// All API operations — chi.HandlerFromMux walks the spec and registers
// one chi route per OpenAPI operation, dispatching to Server methods.
+ // This includes the embedding-provider admin endpoints and the admin
+ // password-reset endpoint; both used to be mounted directly here while
+ // the committed openapi.gen.go lagged the spec, but the file is now
+ // regenerated so the generated mux owns them (a direct mount on top
+ // would double-register and panic).
openapi.HandlerFromMux(srv, r)
- // Embedding-provider admin endpoints — mounted directly because
- // they are not yet in openapi.yaml. The handlers each gate on
- // mustBeAdmin; nothing reaches them without an admin session /
- // API key.
- r.Get("/api/v1/admin/embedding-providers", srv.ListEmbeddingProviders)
- r.Get("/api/v1/admin/embedding-providers/active", srv.GetActiveEmbeddingProvider)
- r.Put("/api/v1/admin/embedding-providers/active", srv.SwitchEmbeddingProvider)
- r.Post("/api/v1/admin/embedding-providers/{kind}/test", srv.TestEmbeddingProvider)
-
return r
}
diff --git a/server/internal/langdetect/langdetect.go b/server/internal/langdetect/langdetect.go
index 4568fdf..eef4755 100644
--- a/server/internal/langdetect/langdetect.go
+++ b/server/internal/langdetect/langdetect.go
@@ -12,29 +12,30 @@ import (
// Ported 1:1 from EXTENSION_MAP in api/app/core/language.py.
var extensionMap = map[string]string{
// Systems / compiled
- ".py": "python",
- ".go": "go",
- ".rs": "rust",
- ".java": "java",
- ".c": "c",
- ".h": "c",
- ".cpp": "cpp",
- ".cc": "cpp",
- ".cxx": "cpp",
- ".hpp": "cpp",
- ".cs": "c_sharp",
+ ".py": "python",
+ ".go": "go",
+ ".rs": "rust",
+ ".java": "java",
+ ".c": "c",
+ ".h": "c",
+ ".cpp": "cpp",
+ ".cc": "cpp",
+ ".cxx": "cpp",
+ ".hpp": "cpp",
+ ".cs": "c_sharp",
".swift": "swift",
- ".kt": "kotlin",
- ".kts": "kotlin",
+ ".kt": "kotlin",
+ ".kts": "kotlin",
".scala": "scala",
- ".zig": "zig",
- ".jl": "julia",
- ".f90": "fortran",
- ".f95": "fortran",
- ".f03": "fortran",
- ".f": "fortran",
- ".m": "objc",
- ".mm": "objc",
+ ".zig": "zig",
+ ".jl": "julia",
+ ".f90": "fortran",
+ ".f95": "fortran",
+ ".f03": "fortran",
+ ".f": "fortran",
+ ".m": "objc",
+ ".mm": "objc",
+ ".sol": "solidity",
// Web / scripting
".ts": "typescript",
".tsx": "tsx",
diff --git a/server/internal/langdetect/langdetect_test.go b/server/internal/langdetect/langdetect_test.go
index 27e94f7..defe8fb 100644
--- a/server/internal/langdetect/langdetect_test.go
+++ b/server/internal/langdetect/langdetect_test.go
@@ -33,8 +33,9 @@ func TestDetect(t *testing.T) {
{"README.md", "markdown"},
{"unknown.xyz", ""},
{"/some/path/to/main.go", "go"},
- {"script.R", "r"}, // uppercase .R
+ {"script.R", "r"}, // uppercase .R
{"script.sh", "bash"},
+ {"Token.sol", "solidity"},
{"build.gradle.kts", "kotlin"},
{"app.kts", "kotlin"},
}
diff --git a/server/internal/users/users.go b/server/internal/users/users.go
index 79ac35d..c5b3a1c 100644
--- a/server/internal/users/users.go
+++ b/server/internal/users/users.go
@@ -32,6 +32,11 @@ const (
// mints a user per fixture crawl).
const defaultBcryptCost = 12
+// MinPasswordLength is the minimum length for an admin-set / user-chosen
+// password. HTTP handlers enforce it at the edge; AdminResetPassword also
+// checks it at the service layer as defense-in-depth for non-HTTP callers.
+const MinPasswordLength = 8
+
// BcryptCost is the work factor actually used by Create / UpdatePassword. It is
// resolved once, at package init, from (highest precedence first):
//
@@ -330,6 +335,33 @@ func (s *Service) UpdatePassword(ctx context.Context, id, newPassword string) er
return nil
}
+// AdminResetPassword sets a new password and FORCES must_change_password=1,
+// mirroring user creation. It is the admin-initiated counterpart to
+// UpdatePassword (which clears the flag for self-service changes): after a
+// reset the user is required to pick a new password on next login. The caller
+// is responsible for revoking the target user's existing sessions — see
+// internal/sessions DeleteAllForUser.
+func (s *Service) AdminResetPassword(ctx context.Context, id, newPassword string) error {
+ if len(newPassword) < MinPasswordLength {
+ return fmt.Errorf("new password must be at least %d characters", MinPasswordLength)
+ }
+ hash, err := bcrypt.GenerateFromPassword([]byte(newPassword), BcryptCost)
+ if err != nil {
+ return fmt.Errorf("hash password: %w", err)
+ }
+ now := time.Now().UTC().Format(time.RFC3339Nano)
+ res, err := s.DB.ExecContext(ctx,
+ `UPDATE users SET password_hash = ?, must_change_password = 1, updated_at = ? WHERE id = ?`,
+ string(hash), now, id)
+ if err != nil {
+ return fmt.Errorf("reset password: %w", err)
+ }
+ if n, _ := res.RowsAffected(); n == 0 {
+ return ErrNotFound
+ }
+ return nil
+}
+
// SetRole changes a user's role. Refuses to demote the last active admin
// to keep the system reachable.
func (s *Service) SetRole(ctx context.Context, id, role string) error {
diff --git a/server/internal/users/users_test.go b/server/internal/users/users_test.go
index 44bc212..8e6df15 100644
--- a/server/internal/users/users_test.go
+++ b/server/internal/users/users_test.go
@@ -89,6 +89,41 @@ func TestUpdatePassword_ClearsMustChange(t *testing.T) {
}
}
+func TestAdminResetPassword_SetsMustChange(t *testing.T) {
+ s := newTestService(t)
+ u, _ := s.Create(context.Background(), "a@b.com", "initial-password", RoleUser, false)
+ if err := s.AdminResetPassword(context.Background(), u.ID, "freshpass123"); err != nil {
+ t.Fatalf("AdminResetPassword: %v", err)
+ }
+ got, err := s.GetByID(context.Background(), u.ID)
+ if err != nil {
+ t.Fatalf("GetByID: %v", err)
+ }
+ if !got.MustChangePassword {
+ t.Errorf("MustChangePassword should be SET after AdminResetPassword")
+ }
+ if _, err := s.Authenticate(context.Background(), "a@b.com", "freshpass123"); err != nil {
+ t.Errorf("Authenticate with reset password: %v", err)
+ }
+ if _, err := s.Authenticate(context.Background(), "a@b.com", "initial-password"); !errors.Is(err, ErrInvalidLogin) {
+ t.Errorf("old password should no longer authenticate, got %v", err)
+ }
+}
+
+func TestAdminResetPassword_RejectsShort(t *testing.T) {
+ s := newTestService(t)
+ u, _ := s.Create(context.Background(), "a@b.com", "initial-password", RoleUser, false)
+ // Service-level defense-in-depth: too-short passwords are refused even
+ // when the HTTP edge check is bypassed.
+ if err := s.AdminResetPassword(context.Background(), u.ID, "short"); err == nil {
+ t.Errorf("AdminResetPassword accepted a %d-char password, want rejection", len("short"))
+ }
+ // The rejected reset must not have mutated the account.
+ if _, err := s.Authenticate(context.Background(), "a@b.com", "initial-password"); err != nil {
+ t.Errorf("original password should still authenticate after rejected reset: %v", err)
+ }
+}
+
func TestSetRole_LastAdminBlock(t *testing.T) {
s := newTestService(t)
a, _ := s.Create(context.Background(), "a@b.com", "password1", RoleAdmin, false)