diff --git a/client/src/components/package-details/MinimalPackageTable.tsx b/client/src/components/package-details/MinimalPackageTable.tsx
index a15a0024..63dfb4c2 100644
--- a/client/src/components/package-details/MinimalPackageTable.tsx
+++ b/client/src/components/package-details/MinimalPackageTable.tsx
@@ -4,12 +4,13 @@ import { ArchDistroString } from '../../types/package-info'
import MinimalPackageTableRow from './MinimalPackageTableRow'
import { useTranslation } from 'react-i18next'
-const MinimalPackageTable: FC<{ packages: (ArchDistroString | string)[] }> = ({
- packages,
-}) => {
+const MinimalPackageTable: FC<{
+ packages: (ArchDistroString | string)[]
+ type: string
+}> = ({ packages, type }) => {
const { t } = useTranslation()
return (
-
+
{t('packageDetails.requiredByModal.name')} |
@@ -21,9 +22,13 @@ const MinimalPackageTable: FC<{ packages: (ArchDistroString | string)[] }> = ({
{packages.map((pkg, i) => (
))}
diff --git a/client/src/components/package-details/MinimalPackageTableRow.tsx b/client/src/components/package-details/MinimalPackageTableRow.tsx
index 7a053376..7bfa6dab 100644
--- a/client/src/components/package-details/MinimalPackageTableRow.tsx
+++ b/client/src/components/package-details/MinimalPackageTableRow.tsx
@@ -10,22 +10,11 @@ import { FC } from 'react'
import { useTranslation } from 'react-i18next'
import { Link as Rlink } from 'react-router-dom'
-const getDescription = (nameWithDescription: string): string | null => {
- return nameWithDescription?.includes(':')
- ? nameWithDescription.split(':')[1].trim()
- : null
-}
-
-const getName = (nameWithDescription: string): string => {
- return nameWithDescription?.includes(':')
- ? nameWithDescription.split(':')[0]
- : nameWithDescription
-}
-
-const MinimalPackageTableRow: FC<{ pkg: string; external: boolean }> = ({
- pkg,
- external,
-}) => {
+const MinimalPackageTableRow: FC<{
+ pkg: string
+ description: string
+ external: boolean
+}> = ({ pkg, description, external }) => {
const { t } = useTranslation()
return (
@@ -34,13 +23,13 @@ const MinimalPackageTableRow: FC<{ pkg: string; external: boolean }> = ({
{external ? (
- <>{getName(pkg)}>
+ <>{pkg}>
) : (
= ({
'pink.600',
'pink.400',
)}
- to={`/packages/${getName(pkg)}`}
+ to={`/packages/${pkg}`}
>
- {getName(pkg)}
+ {pkg}
)}
diff --git a/client/src/components/package-details/PackageDependenciesModal.tsx b/client/src/components/package-details/PackageDependenciesModal.tsx
index fa9bfa10..2086c0d9 100644
--- a/client/src/components/package-details/PackageDependenciesModal.tsx
+++ b/client/src/components/package-details/PackageDependenciesModal.tsx
@@ -51,6 +51,7 @@ const PackageDependenciesModal: FC<{ name: string } & UseDisclosureProps> = ({
packages={
data!.runtimeDependencies || []
}
+ type='runtimeDependencies'
/>
)}
@@ -64,6 +65,7 @@ const PackageDependenciesModal: FC<{ name: string } & UseDisclosureProps> = ({
)}
@@ -79,6 +81,7 @@ const PackageDependenciesModal: FC<{ name: string } & UseDisclosureProps> = ({
packages={
data!.optionalDependencies || []
}
+ type='optionalDependencies'
/>
)}
@@ -94,6 +97,7 @@ const PackageDependenciesModal: FC<{ name: string } & UseDisclosureProps> = ({
packages={
data!.pacstallDependencies || []
}
+ type='pacstallDependencies'
/>
)}
diff --git a/client/src/components/package-details/PackageDetailsHeader.tsx b/client/src/components/package-details/PackageDetailsHeader.tsx
index 84a5074e..e78fb352 100644
--- a/client/src/components/package-details/PackageDetailsHeader.tsx
+++ b/client/src/components/package-details/PackageDetailsHeader.tsx
@@ -1,7 +1,6 @@
import { HStack, Heading, Text } from '@chakra-ui/react'
import { FC } from 'react'
import PackageInfo from '../../types/package-info'
-import InstallNowButton from './InstallNowButton'
const PackageDetailsHeader: FC<{ data: PackageInfo; isMobile: boolean }> = (
{ data },
@@ -13,7 +12,6 @@ const PackageDetailsHeader: FC<{ data: PackageInfo; isMobile: boolean }> = (
{data.packageName}
- {!isMobile && }
{data.description}
diff --git a/client/src/components/package-details/PackageDetailsPage.tsx b/client/src/components/package-details/PackageDetailsPage.tsx
index d00aa32b..5c7ce68a 100644
--- a/client/src/components/package-details/PackageDetailsPage.tsx
+++ b/client/src/components/package-details/PackageDetailsPage.tsx
@@ -52,7 +52,13 @@ const PackageDetailsPage: FC = ({
requiredByModal={requiredByModal}
/>
1
+ ? data.baseIndex === 0
+ ? `${data.packageBase}:pkgbase`
+ : `${data.packageBase}:${data.packageName}`
+ : data.packageName
+ }
prettyName={data.packageName}
isMobile={isMobile}
/>
diff --git a/client/src/components/package-details/PackageDetailsTable.tsx b/client/src/components/package-details/PackageDetailsTable.tsx
index 3701a4a4..ecfdfe71 100644
--- a/client/src/components/package-details/PackageDetailsTable.tsx
+++ b/client/src/components/package-details/PackageDetailsTable.tsx
@@ -114,7 +114,7 @@ const PackageDetailsTable: FC<{
{t('packageDetails.openInGithub')}{' '}
= ({
const { data, loading, error } = usePackageRequiredBy(name)
const { t } = useTranslation()
- const ComputedPackageList = () =>
+ const ComputedPackageList = () => (
+
+ )
return (
diff --git a/client/src/components/packages/PackageTableRow.tsx b/client/src/components/packages/PackageTableRow.tsx
index da198715..6e4c0abe 100644
--- a/client/src/components/packages/PackageTableRow.tsx
+++ b/client/src/components/packages/PackageTableRow.tsx
@@ -90,7 +90,16 @@ const PackageTableRow: FC<{ pkg: PackageInfo; disabled?: boolean }> = ({
display={useBreakpointValue({ base: 'none', md: 'table-cell' })}
>
-
+ 1
+ ? pkg.baseIndex === 0
+ ? `${pkg.packageBase}:pkgbase`
+ : `${pkg.packageBase}:${pkg.packageName}`
+ : pkg.packageName
+ }
+ />
diff --git a/client/src/hooks/usePackageDependencies.ts b/client/src/hooks/usePackageDependencies.ts
index dcfa19d6..76632b65 100644
--- a/client/src/hooks/usePackageDependencies.ts
+++ b/client/src/hooks/usePackageDependencies.ts
@@ -9,20 +9,50 @@ const usePackageDependencies = (name: string) => {
const [error, setError] = useState(false)
useEffect(() => {
- setError(false)
- setLoading(true)
- axios
- .get(
- serverConfig.host + `/api/packages/${name}/dependencies`,
- )
- .then(result => {
+ const fetchDependencies = async () => {
+ setError(false)
+ setLoading(true)
+
+ try {
+ const result = await axios.get(
+ `${serverConfig.host}/api/packages/${name}/dependencies`,
+ )
+
+ const pacdeps = result.data.pacstallDependencies || []
+
+ const descriptionDeps = await Promise.all(
+ pacdeps.map(async dep => {
+ try {
+ const depResult = await axios.get(
+ `${serverConfig.host}/api/packages/${dep.value}`,
+ )
+ return {
+ ...dep,
+ description: depResult.data.description,
+ }
+ } catch (e) {
+ console.error(
+ `Failed to fetch description for ${dep.value}`,
+ e,
+ )
+ return { ...dep, description: null }
+ }
+ }),
+ )
+
+ setData({
+ ...result.data,
+ pacstallDependencies: descriptionDeps,
+ })
setLoading(false)
- setData(result.data)
- })
- .catch(() => {
+ } catch (e) {
+ console.error('Error fetching package dependencies:', e)
setError(true)
setLoading(false)
- })
+ }
+ }
+
+ fetchDependencies()
}, [name])
return {
diff --git a/client/src/types/package-info.ts b/client/src/types/package-info.ts
index ea9b3292..bcf2a52d 100644
--- a/client/src/types/package-info.ts
+++ b/client/src/types/package-info.ts
@@ -1,8 +1,12 @@
export default interface PackageInfo {
packageName: string
prettyName: string
+ packageBase: string
+ baseIndex: int
+ baseTotal: int
description: string
version: string
+ sourceVersion: string
release: string
epoch: string
latestVersion?: string
diff --git a/server/types/pac/parser/last_updated.go b/server/types/pac/parser/last_updated.go
index adf1bb8d..2cf4236b 100644
--- a/server/types/pac/parser/last_updated.go
+++ b/server/types/pac/parser/last_updated.go
@@ -85,7 +85,7 @@ func setLastUpdatedAt(packages []*pac.Script) error {
for _, pkg := range packages {
if tuple, err := array.FindBy(lastUpdatedTuples, func(tuple packageLastUpdatedTuple) bool {
- return tuple.packageName == pkg.PackageName
+ return tuple.packageName == pkg.PackageBase
}); err == nil {
pkg.LastUpdatedAt = tuple.lastUpdated
} else {
diff --git a/server/types/pac/parser/pacsh/git_version.go b/server/types/pac/parser/pacsh/git_version.go
index c40d00f9..e5ee12df 100644
--- a/server/types/pac/parser/pacsh/git_version.go
+++ b/server/types/pac/parser/pacsh/git_version.go
@@ -18,8 +18,10 @@ func ApplyGitVersion(p *pac.Script) error {
}
if p.Epoch != "" {
+ p.SourceVersion = version
p.Version = p.Epoch + ":" + version + "-" + p.Release
} else {
+ p.SourceVersion = version
p.Version = version + "-" + p.Release
}
diff --git a/server/types/pac/parser/pacsh/parse_pac_output.go b/server/types/pac/parser/pacsh/parse_pac_output.go
index 21fd336f..91aa5f3a 100644
--- a/server/types/pac/parser/pacsh/parse_pac_output.go
+++ b/server/types/pac/parser/pacsh/parse_pac_output.go
@@ -5,15 +5,17 @@ import (
"pacstall.dev/webserver/types/pac"
)
-func ParsePacOutput(data []byte) (*pac.Script, error) {
+func ParsePacOutput(data []byte) ([]*pac.Script, error) {
+ var scripts []*pac.Script
out, err := srcinfo.Parse(string(data))
if err != nil {
return nil, err
}
- ps := pac.FromSrcInfo(*out)
+ scripts = pac.FromSrcInfo(*out)
+ for idx := range scripts {
+ scripts[idx].PrettyName = getPrettyName(scripts[idx])
+ }
- ps.PrettyName = getPrettyName(ps)
-
- return ps, nil
+ return scripts, nil
}
diff --git a/server/types/pac/parser/parse.go b/server/types/pac/parser/parse.go
index 26eca283..e6fa9de5 100644
--- a/server/types/pac/parser/parse.go
+++ b/server/types/pac/parser/parse.go
@@ -66,7 +66,7 @@ func ParseAll() error {
}))
pacstore.Update(loadedPacscripts)
- log.Info("successfully loaded %v (%v / %v) packages", types.Percent(float64(len(loadedPacscripts))/float64(len(pkgList))), len(loadedPacscripts), len(pkgList))
+ log.Info("successfully loaded %v packages from %v pacscripts", len(loadedPacscripts), len(pkgList))
return nil
}
@@ -79,11 +79,19 @@ func readKnownPacscriptNames() ([]string, error) {
}
names := strings.Split(strings.TrimSpace(string(bytes)), "\n")
- for idx := range names {
- names[idx] = strings.TrimSpace(names[idx])
- }
+ var filteredNames []string
+
+ for idx := range names {
+ names[idx] = strings.TrimSpace(names[idx])
+
+ if strings.HasSuffix(names[idx], ":pkgbase") {
+ filteredNames = append(filteredNames, strings.TrimSuffix(names[idx], ":pkgbase"))
+ } else if !strings.Contains(names[idx], ":") {
+ filteredNames = append(filteredNames, names[idx])
+ }
+ }
- return names, nil
+ return filteredNames, nil
}
func parsePacscriptFiles(names []string) ([]*pac.Script, error) {
@@ -92,19 +100,26 @@ func parsePacscriptFiles(names []string) ([]*pac.Script, error) {
}
log.Info("parsing pacscripts...")
- outChan := batch.Run(int(config.MaxOpenFiles), names, func(pacName string) (*pac.Script, error) {
+ outChan := batch.Run(int(config.MaxOpenFiles), names, func(pacName string) ([]*pac.Script, error) {
out, err := ParsePacscriptFile(config.GitClonePath, pacName)
if config.Repology.Enabled {
- if err := repology.Sync(out); err != nil {
- log.Debug("failed to sync %v with repology. Error: %+v", pacName, err)
- }
+ for _, script := range out {
+ if err := repology.Sync(script); err != nil {
+ log.Debug("failed to sync %v with repology. Error: %+v", pacName, err)
+ }
+ }
}
return out, err
})
+ results := channels.ToSlice(outChan)
+ var allScripts []*pac.Script
+ for _, scripts := range results {
+ allScripts = append(allScripts, scripts...)
+ }
- return channels.ToSlice(outChan), nil
+ return allScripts, nil
}
func readPacscriptFile(rootDir, name string) (scriptBytes []byte, fileName string, err error) {
@@ -118,7 +133,7 @@ func readPacscriptFile(rootDir, name string) (scriptBytes []byte, fileName strin
return scriptBytes, consts.SRCINFO_FILE_EXTENSION, nil
}
-func ParsePacscriptFile(programsDirPath, name string) (*pac.Script, error) {
+func ParsePacscriptFile(programsDirPath, name string) ([]*pac.Script, error) {
srcInfoData, _, err := readPacscriptFile(programsDirPath, name)
if err != nil {
return nil, errorx.Decorate(err, "failed to read pacscript '%v'", name)
diff --git a/server/types/pac/parser/search.go b/server/types/pac/parser/search.go
index f1b99407..63252601 100644
--- a/server/types/pac/parser/search.go
+++ b/server/types/pac/parser/search.go
@@ -37,6 +37,7 @@ func FilterPackages(packages []*pac.Script, filter, filterBy string) []*pac.Scri
case "name":
return filterByFunc(func(pi *pac.Script) bool {
return strings.Contains(pi.PackageName, filter) ||
+ strings.Contains(pi.PackageBase, filter) ||
func(ps []pac.ArchDistroString, filter string) bool {
return array.Any(ps, func(it pac.ArchDistroString) bool {
return strings.Contains(it.Value, filter)
diff --git a/server/types/pac/script.go b/server/types/pac/script.go
index dd53b5a1..e48524c1 100644
--- a/server/types/pac/script.go
+++ b/server/types/pac/script.go
@@ -45,8 +45,12 @@ func (a ArchDistroString) Equals(b types.Equaller) bool {
type Script struct {
PackageName string `json:"packageName"`
PrettyName string `json:"prettyName"`
+ PackageBase string `json:"packageBase"`
+ BaseIndex int `json:"baseIndex"`
+ BaseTotal int `json:"baseTotal"`
Description string `json:"description"`
Version string `json:"version"`
+ SourceVersion string `json:"sourceVersion"`
Release string `json:"release"`
Epoch string `json:"epoch"`
LatestVersion *string `json:"latestVersion"`
@@ -99,51 +103,137 @@ func (p *Script) Type() types.PackageTypeName {
return types.PackageTypeSuffixToPackageTypeName["-git"]
}
-func FromSrcInfo(info srcinfo.Srcinfo) *Script {
- return &Script{
- PackageName: info.Packages[0].Pkgname, // needs to be looped for every pkgname within pkgbase
- PrettyName: "",
- Description: info.Pkgdesc,
- Version: info.Version(),
- Release: info.Pkgrel,
- Epoch: info.Epoch,
- LatestVersion: nil,
- Homepage: info.URL,
- Priority: info.Priority,
- Architectures: info.Arch,
- License: orEmptyArray(info.License),
- Gives: toArchDistroStrings(info.Gives),
- RuntimeDependencies: toArchDistroStrings(info.Depends),
- CheckDependencies: toArchDistroStrings(info.CheckDepends),
- BuildDependencies: toArchDistroStrings(info.MakeDepends),
- OptionalDependencies: toArchDistroStrings(info.OptDepends),
- PacstallDependencies: toArchDistroStrings(info.Pacdeps),
- CheckConflicts: toArchDistroStrings(info.CheckConflicts),
- BuildConflicts: toArchDistroStrings(info.MakeConflicts),
- Conflicts: toArchDistroStrings(info.Conflicts),
- Provides: toArchDistroStrings(info.Provides),
- Breaks: toArchDistroStrings(info.Breaks),
- Replaces: toArchDistroStrings(info.Replaces),
- Enhances: toArchDistroStrings(info.Enhances),
- Recommends: toArchDistroStrings(info.Recommends),
- Suggests: toArchDistroStrings(info.Suggests),
- Mask: orEmptyArray(info.Mask),
- Compatible: orEmptyArray(info.Compatible),
- Incompatible: orEmptyArray(info.Incompatible),
- Maintainers: info.Maintainer,
- Source: toSourceStrings(info.Source),
- NoExtract: orEmptyArray(info.NoExtract),
- NoSubmodules: orEmptyArray(info.NoSubmodules),
- Md5Sums: toArchDistroStrings(info.MD5Sums),
- Sha1Sums: toArchDistroStrings(info.SHA1Sums),
- Sha224Sums: toArchDistroStrings(info.SHA224Sums),
- Sha256Sums: toArchDistroStrings(info.SHA256Sums),
- Sha384Sums: toArchDistroStrings(info.SHA384Sums),
- Sha512Sums: toArchDistroStrings(info.SHA512Sums),
- Backup: orEmptyArray(info.Backup),
- Repology: info.Repology,
- RequiredBy: []string{},
- UpdateStatus: UpdateStatus.Unknown,
+func FromSrcInfo(info srcinfo.Srcinfo) []*Script {
+ var scripts []*Script
+ if len(info.Packages) > 1 {
+ scripts = append(scripts, &Script{
+ PackageName: info.Pkgbase,
+ PrettyName: "",
+ PackageBase: info.Pkgbase,
+ BaseIndex: 0,
+ BaseTotal: len(info.Packages),
+ Description: info.Pkgdesc,
+ Version: info.Version(),
+ SourceVersion: info.Pkgver,
+ Release: info.Pkgrel,
+ Epoch: info.Epoch,
+ LatestVersion: nil,
+ Homepage: info.URL,
+ Priority: info.Priority,
+ Architectures: info.Arch,
+ License: orEmptyArray(info.License),
+ Gives: toArchDistroStrings(info.Gives),
+ RuntimeDependencies: toArchDistroStrings(info.Depends),
+ CheckDependencies: toArchDistroStrings(info.CheckDepends),
+ BuildDependencies: toArchDistroStrings(info.MakeDepends),
+ OptionalDependencies: toArchDistroStrings(info.OptDepends),
+ PacstallDependencies: toArchDistroStrings(info.Pacdeps),
+ CheckConflicts: toArchDistroStrings(info.CheckConflicts),
+ BuildConflicts: toArchDistroStrings(info.MakeConflicts),
+ Conflicts: toArchDistroStrings(info.Conflicts),
+ Provides: toArchDistroStrings(info.Provides),
+ Breaks: toArchDistroStrings(info.Breaks),
+ Replaces: toArchDistroStrings(info.Replaces),
+ Enhances: toArchDistroStrings(info.Enhances),
+ Recommends: toArchDistroStrings(info.Recommends),
+ Suggests: toArchDistroStrings(info.Suggests),
+ Mask: orEmptyArray(info.Mask),
+ Compatible: orEmptyArray(info.Compatible),
+ Incompatible: orEmptyArray(info.Incompatible),
+ Maintainers: info.Maintainer,
+ Source: toSourceStrings(info.Source),
+ NoExtract: orEmptyArray(info.NoExtract),
+ NoSubmodules: orEmptyArray(info.NoSubmodules),
+ Md5Sums: toArchDistroStrings(info.MD5Sums),
+ Sha1Sums: toArchDistroStrings(info.SHA1Sums),
+ Sha224Sums: toArchDistroStrings(info.SHA224Sums),
+ Sha256Sums: toArchDistroStrings(info.SHA256Sums),
+ Sha384Sums: toArchDistroStrings(info.SHA384Sums),
+ Sha512Sums: toArchDistroStrings(info.SHA512Sums),
+ Backup: orEmptyArray(info.Backup),
+ Repology: info.Repology,
+ RequiredBy: []string{},
+ UpdateStatus: UpdateStatus.Unknown,
+ })
+ }
+ for i, pkg := range info.Packages {
+ scripts = append(scripts, &Script{
+ PackageName: pkg.Pkgname,
+ PrettyName: "",
+ PackageBase: info.Pkgbase,
+ BaseIndex: i + 1,
+ BaseTotal: len(info.Packages),
+ Description: fallback[string, string](pkg.Pkgdesc, info.Pkgdesc, nil),
+ Version: info.Version(),
+ SourceVersion: info.Pkgver,
+ Release: info.Pkgrel,
+ Epoch: info.Epoch,
+ LatestVersion: nil,
+ Homepage: info.URL,
+ Priority: fallback[string, string](pkg.Priority, info.Priority, nil),
+ Architectures: info.Arch,
+ License: fallback(pkg.License, info.License, orEmptyArray),
+ Gives: fallback(pkg.Gives, info.Gives, toArchDistroStrings),
+ RuntimeDependencies: fallback(pkg.Depends, info.Depends, toArchDistroStrings),
+ CheckDependencies: fallback(pkg.CheckDepends, info.CheckDepends, toArchDistroStrings),
+ BuildDependencies: toArchDistroStrings(info.MakeDepends),
+ OptionalDependencies: fallback(pkg.OptDepends, info.OptDepends, toArchDistroStrings),
+ PacstallDependencies: fallback(pkg.Pacdeps, info.Pacdeps, toArchDistroStrings),
+ CheckConflicts: fallback(pkg.CheckConflicts, info.CheckConflicts, toArchDistroStrings),
+ BuildConflicts: toArchDistroStrings(info.MakeConflicts),
+ Conflicts: fallback(pkg.Conflicts, info.Conflicts, toArchDistroStrings),
+ Provides: fallback(pkg.Provides, info.Provides, toArchDistroStrings),
+ Breaks: fallback(pkg.Breaks, info.Breaks, toArchDistroStrings),
+ Replaces: fallback(pkg.Replaces, info.Replaces, toArchDistroStrings),
+ Enhances: fallback(pkg.Enhances, info.Enhances, toArchDistroStrings),
+ Recommends: fallback(pkg.Recommends, info.Recommends, toArchDistroStrings),
+ Suggests: fallback(pkg.Suggests, info.Suggests, toArchDistroStrings),
+ Mask: orEmptyArray(info.Mask),
+ Compatible: orEmptyArray(info.Compatible),
+ Incompatible: orEmptyArray(info.Incompatible),
+ Maintainers: info.Maintainer,
+ Source: toSourceStrings(info.Source),
+ NoExtract: orEmptyArray(info.NoExtract),
+ NoSubmodules: orEmptyArray(info.NoSubmodules),
+ Md5Sums: toArchDistroStrings(info.MD5Sums),
+ Sha1Sums: toArchDistroStrings(info.SHA1Sums),
+ Sha224Sums: toArchDistroStrings(info.SHA224Sums),
+ Sha256Sums: toArchDistroStrings(info.SHA256Sums),
+ Sha384Sums: toArchDistroStrings(info.SHA384Sums),
+ Sha512Sums: toArchDistroStrings(info.SHA512Sums),
+ Backup: fallback(pkg.Backup, info.Backup, orEmptyArray),
+ Repology: fallback(pkg.Repology, info.Repology, orEmptyArray),
+ RequiredBy: []string{},
+ UpdateStatus: UpdateStatus.Unknown,
+ })
+ }
+
+ return scripts
+}
+
+func fallback[T any, R any](pkgValue, infoValue T, transform func(T) R) R {
+ if isNonEmpty(pkgValue) {
+ if transform != nil {
+ return transform(pkgValue)
+ }
+ return any(pkgValue).(R)
+ }
+ if transform != nil {
+ return transform(infoValue)
+ }
+ return any(infoValue).(R)
+}
+
+func isNonEmpty[T any](value T) bool {
+ switch v := any(value).(type) {
+ case string:
+ return v != ""
+ case []string:
+ return len(v) > 0
+ case []srcinfo.ArchDistroString:
+ return len(v) > 0
+ default:
+ return true
}
}