Some frontend cleanup (#459)
* remove Debug.log statements * move View.Components.SearchInput.viewBucket into Search module * combine 2 version of viewSearchInput * moving viewFlakes function to Search module and removing View.Components.SearchInput module * removing View.Components module * use :: instead of List.append
This commit is contained in:
parent
b316bc13cc
commit
b389e378c2
|
@ -162,19 +162,12 @@ attemptQuery (( model, _ ) as pair) =
|
||||||
|
|
||||||
Flakes (PackagesModel searchModel) ->
|
Flakes (PackagesModel searchModel) ->
|
||||||
if Search.shouldLoad searchModel then
|
if Search.shouldLoad searchModel then
|
||||||
-- let
|
|
||||||
-- _ = Debug.log "main" "submit flake message"
|
|
||||||
-- in
|
|
||||||
submitQuery FlakesMsg Page.Flakes.makeRequest { searchModel | channel = defaultFlakeId }
|
submitQuery FlakesMsg Page.Flakes.makeRequest { searchModel | channel = defaultFlakeId }
|
||||||
|
|
||||||
else
|
else
|
||||||
-- let _ = Debug.log "main" "should not load flakes" in
|
|
||||||
noEffects pair
|
noEffects pair
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
-- let
|
|
||||||
-- _ = Debug.log "pair" <| Debug.toString pair
|
|
||||||
-- in
|
|
||||||
pair
|
pair
|
||||||
|
|
||||||
|
|
||||||
|
@ -268,7 +261,6 @@ changeRouteTo currentModel url =
|
||||||
|
|
||||||
Route.Flakes searchArgs ->
|
Route.Flakes searchArgs ->
|
||||||
let
|
let
|
||||||
-- _ = Debug.log "changeRouteTo" "flakes"
|
|
||||||
modelPage =
|
modelPage =
|
||||||
case model.page of
|
case model.page of
|
||||||
Flakes x ->
|
Flakes x ->
|
||||||
|
@ -285,8 +277,6 @@ changeRouteTo currentModel url =
|
||||||
|
|
||||||
update : Msg -> Model -> ( Model, Cmd Msg )
|
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||||
update msg model =
|
update msg model =
|
||||||
-- let _ = Debug.log "main" "update"
|
|
||||||
-- in
|
|
||||||
case ( msg, model.page ) of
|
case ( msg, model.page ) of
|
||||||
( ClickedLink urlRequest, _ ) ->
|
( ClickedLink urlRequest, _ ) ->
|
||||||
case urlRequest of
|
case urlRequest of
|
||||||
|
|
|
@ -12,20 +12,33 @@ import Html
|
||||||
exposing
|
exposing
|
||||||
( Html
|
( Html
|
||||||
, a
|
, a
|
||||||
|
, div
|
||||||
|
, h1
|
||||||
, strong
|
, strong
|
||||||
, text
|
, text
|
||||||
)
|
)
|
||||||
import Html.Attributes exposing (href)
|
import Html.Attributes
|
||||||
|
exposing
|
||||||
|
( class
|
||||||
|
, href
|
||||||
|
)
|
||||||
|
import Html.Events exposing (onClick)
|
||||||
import Http exposing (Body)
|
import Http exposing (Body)
|
||||||
import Page.Options exposing (Msg(..))
|
import Page.Options exposing (Msg(..))
|
||||||
import Page.Packages exposing (Msg(..))
|
import Page.Packages exposing (Msg(..))
|
||||||
|
import RemoteData exposing (RemoteData(..))
|
||||||
import Route
|
import Route
|
||||||
exposing
|
exposing
|
||||||
( Route(..)
|
( Route(..)
|
||||||
, SearchType(..)
|
, SearchType(..)
|
||||||
)
|
)
|
||||||
import Search
|
import Search
|
||||||
import View.Components
|
exposing
|
||||||
|
( Msg(..)
|
||||||
|
, viewFlakes
|
||||||
|
, viewResult
|
||||||
|
, viewSearchInput
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -124,14 +137,44 @@ update navKey msg model =
|
||||||
view : Model -> Html Msg
|
view : Model -> Html Msg
|
||||||
view model =
|
view model =
|
||||||
let
|
let
|
||||||
mkBody categoryName =
|
resultStatus result =
|
||||||
View.Components.body { toRoute = Route.Flakes, categoryName = categoryName }
|
case result of
|
||||||
[ text "Search packages and options of "
|
RemoteData.NotAsked ->
|
||||||
, strong []
|
"not-asked"
|
||||||
[ a
|
|
||||||
[ href "https://github.com/NixOS/nixos-search/blob/main/flakes/manual.toml" ]
|
RemoteData.Loading ->
|
||||||
[ text "public flakes" ]
|
"loading"
|
||||||
]
|
|
||||||
|
RemoteData.Success _ ->
|
||||||
|
"success"
|
||||||
|
|
||||||
|
RemoteData.Failure _ ->
|
||||||
|
"failure"
|
||||||
|
|
||||||
|
bodyTitle =
|
||||||
|
[ text "Search packages and options of "
|
||||||
|
, strong []
|
||||||
|
[ a
|
||||||
|
[ href "https://github.com/NixOS/nixos-search/blob/main/flakes/manual.toml" ]
|
||||||
|
[ text "public flakes" ]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
mkBody categoryName model_ viewSuccess viewBuckets outMsg =
|
||||||
|
div
|
||||||
|
(List.append
|
||||||
|
[ class <| "search-page " ++ resultStatus model_.result ]
|
||||||
|
(if model_.showSort then
|
||||||
|
[ onClick (outMsg ToggleSort) ]
|
||||||
|
|
||||||
|
else
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
[ h1 [] bodyTitle
|
||||||
|
, viewSearchInput outMsg categoryName Nothing model_.query
|
||||||
|
, viewResult outMsg Route.Flakes categoryName model_ viewSuccess viewBuckets <|
|
||||||
|
viewFlakes outMsg model_.channel model_.searchType
|
||||||
]
|
]
|
||||||
|
|
||||||
body =
|
body =
|
||||||
|
|
|
@ -52,9 +52,9 @@ import Search
|
||||||
exposing
|
exposing
|
||||||
( Details(..)
|
( Details(..)
|
||||||
, decodeResolvedFlake
|
, decodeResolvedFlake
|
||||||
|
, viewBucket
|
||||||
)
|
)
|
||||||
import Utils
|
import Utils
|
||||||
import View.Components.SearchInput exposing (viewBucket)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -167,9 +167,6 @@ init searchArgs model =
|
||||||
let
|
let
|
||||||
( newModel, newCmd ) =
|
( newModel, newCmd ) =
|
||||||
Search.init searchArgs model
|
Search.init searchArgs model
|
||||||
|
|
||||||
-- _ =
|
|
||||||
-- Debug.log "New package model" newModel
|
|
||||||
in
|
in
|
||||||
( newModel
|
( newModel
|
||||||
, Cmd.map SearchMsg newCmd
|
, Cmd.map SearchMsg newCmd
|
||||||
|
|
|
@ -11,6 +11,7 @@ module Search exposing
|
||||||
, Sort(..)
|
, Sort(..)
|
||||||
, channelDetailsFromId
|
, channelDetailsFromId
|
||||||
, channels
|
, channels
|
||||||
|
, closeButton
|
||||||
, decodeAggregation
|
, decodeAggregation
|
||||||
, decodeResolvedFlake
|
, decodeResolvedFlake
|
||||||
, decodeResult
|
, decodeResult
|
||||||
|
@ -26,7 +27,10 @@ module Search exposing
|
||||||
, trapClick
|
, trapClick
|
||||||
, update
|
, update
|
||||||
, view
|
, view
|
||||||
|
, viewBucket
|
||||||
|
, viewFlakes
|
||||||
, viewResult
|
, viewResult
|
||||||
|
, viewSearchInput
|
||||||
)
|
)
|
||||||
|
|
||||||
import Base64
|
import Base64
|
||||||
|
@ -74,7 +78,12 @@ import Json.Decode
|
||||||
import Json.Decode.Pipeline
|
import Json.Decode.Pipeline
|
||||||
import Json.Encode
|
import Json.Encode
|
||||||
import RemoteData
|
import RemoteData
|
||||||
import Route exposing (SearchType)
|
import Route
|
||||||
|
exposing
|
||||||
|
( SearchType
|
||||||
|
, allTypes
|
||||||
|
, searchTypeToTitle
|
||||||
|
)
|
||||||
import Route.SearchQuery
|
import Route.SearchQuery
|
||||||
import Set
|
import Set
|
||||||
import Task
|
import Task
|
||||||
|
@ -398,10 +407,6 @@ update toRoute navKey msg model =
|
||||||
|> pushUrl toRoute navKey
|
|> pushUrl toRoute navKey
|
||||||
|
|
||||||
QueryResponse result ->
|
QueryResponse result ->
|
||||||
-- let
|
|
||||||
-- _ =
|
|
||||||
-- Debug.log "got query result" result
|
|
||||||
-- in
|
|
||||||
( { model
|
( { model
|
||||||
| result = result
|
| result = result
|
||||||
}
|
}
|
||||||
|
@ -768,11 +773,42 @@ view { toRoute, categoryName } title model viewSuccess viewBuckets outMsg search
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
[ h1 [] title
|
[ h1 [] title
|
||||||
, viewSearchInput outMsg categoryName model.channel model.query
|
, viewSearchInput outMsg categoryName (Just model.channel) model.query
|
||||||
, viewResult outMsg toRoute categoryName model viewSuccess viewBuckets searchBuckets
|
, viewResult outMsg toRoute categoryName model viewSuccess viewBuckets searchBuckets
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
viewFlakes :
|
||||||
|
(Msg a b -> msg)
|
||||||
|
-> String
|
||||||
|
-> SearchType
|
||||||
|
-> List (Html msg)
|
||||||
|
viewFlakes outMsg _ selectedCategory =
|
||||||
|
[ li []
|
||||||
|
[ ul []
|
||||||
|
(List.map
|
||||||
|
(\category ->
|
||||||
|
li []
|
||||||
|
[ a
|
||||||
|
[ href "#"
|
||||||
|
, onClick <| outMsg (SubjectChange category)
|
||||||
|
, classList
|
||||||
|
[ ( "selected"
|
||||||
|
, category == selectedCategory
|
||||||
|
)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
[ span [] [ text <| searchTypeToTitle category ]
|
||||||
|
, closeButton
|
||||||
|
]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
allTypes
|
||||||
|
)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
viewResult :
|
viewResult :
|
||||||
(Msg a b -> c)
|
(Msg a b -> c)
|
||||||
-> Route.SearchRoute
|
-> Route.SearchRoute
|
||||||
|
@ -871,10 +907,62 @@ viewNoResults categoryName =
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
closeButton : Html a
|
||||||
|
closeButton =
|
||||||
|
span [] []
|
||||||
|
|
||||||
|
|
||||||
|
viewBucket :
|
||||||
|
String
|
||||||
|
-> List AggregationsBucketItem
|
||||||
|
-> (String -> a)
|
||||||
|
-> List String
|
||||||
|
-> List (Html a)
|
||||||
|
-> List (Html a)
|
||||||
|
viewBucket title buckets searchMsgFor selectedBucket sets =
|
||||||
|
List.append
|
||||||
|
sets
|
||||||
|
(if List.isEmpty buckets then
|
||||||
|
[]
|
||||||
|
|
||||||
|
else
|
||||||
|
[ li []
|
||||||
|
[ ul []
|
||||||
|
(List.append
|
||||||
|
[ li [ class "header" ] [ text title ] ]
|
||||||
|
(List.map
|
||||||
|
(\bucket ->
|
||||||
|
li []
|
||||||
|
[ a
|
||||||
|
[ href "#"
|
||||||
|
, onClick <| searchMsgFor bucket.key
|
||||||
|
, classList
|
||||||
|
[ ( "selected"
|
||||||
|
, List.member bucket.key selectedBucket
|
||||||
|
)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
[ span [] [ text bucket.key ]
|
||||||
|
, if List.member bucket.key selectedBucket then
|
||||||
|
closeButton
|
||||||
|
|
||||||
|
else
|
||||||
|
span [] [ span [ class "badge" ] [ text <| String.fromInt bucket.doc_count ] ]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
buckets
|
||||||
|
)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
viewSearchInput :
|
viewSearchInput :
|
||||||
(Msg a b -> c)
|
(Msg a b -> c)
|
||||||
-> String
|
-> String
|
||||||
-> String
|
-> Maybe String
|
||||||
-> Maybe String
|
-> Maybe String
|
||||||
-> Html c
|
-> Html c
|
||||||
viewSearchInput outMsg categoryName selectedChannel searchQuery =
|
viewSearchInput outMsg categoryName selectedChannel searchQuery =
|
||||||
|
@ -882,7 +970,7 @@ viewSearchInput outMsg categoryName selectedChannel searchQuery =
|
||||||
[ onSubmit (outMsg QueryInputSubmit)
|
[ onSubmit (outMsg QueryInputSubmit)
|
||||||
, class "search-input"
|
, class "search-input"
|
||||||
]
|
]
|
||||||
[ div []
|
(div []
|
||||||
[ div []
|
[ div []
|
||||||
[ input
|
[ input
|
||||||
[ type_ "text"
|
[ type_ "text"
|
||||||
|
@ -897,8 +985,11 @@ viewSearchInput outMsg categoryName selectedChannel searchQuery =
|
||||||
, button [ class "btn", type_ "submit" ]
|
, button [ class "btn", type_ "submit" ]
|
||||||
[ text "Search" ]
|
[ text "Search" ]
|
||||||
]
|
]
|
||||||
, div [] (viewChannels outMsg selectedChannel)
|
:: (selectedChannel
|
||||||
]
|
|> Maybe.map (\x -> [ div [] (viewChannels outMsg x) ])
|
||||||
|
|> Maybe.withDefault []
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
viewChannels :
|
viewChannels :
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
module View.Components exposing (body)
|
|
||||||
|
|
||||||
import Html exposing (Html)
|
|
||||||
import Route exposing (SearchRoute)
|
|
||||||
import Search
|
|
||||||
exposing
|
|
||||||
( Details
|
|
||||||
, Model
|
|
||||||
, Msg
|
|
||||||
, ResultItem
|
|
||||||
, SearchResult
|
|
||||||
)
|
|
||||||
import View.Components.Body
|
|
||||||
|
|
||||||
|
|
||||||
body :
|
|
||||||
{ toRoute : SearchRoute, categoryName : String }
|
|
||||||
-> List (Html c)
|
|
||||||
-> Model a b
|
|
||||||
->
|
|
||||||
(String
|
|
||||||
-> Details
|
|
||||||
-> Maybe String
|
|
||||||
-> List (ResultItem a)
|
|
||||||
-> Html c
|
|
||||||
)
|
|
||||||
->
|
|
||||||
(Maybe String
|
|
||||||
-> SearchResult a b
|
|
||||||
-> List (Html c)
|
|
||||||
)
|
|
||||||
-> (Msg a b -> c)
|
|
||||||
-> Html c
|
|
||||||
body =
|
|
||||||
View.Components.Body.view
|
|
|
@ -1,78 +0,0 @@
|
||||||
module View.Components.Body exposing (view)
|
|
||||||
|
|
||||||
import Html
|
|
||||||
exposing
|
|
||||||
( Html
|
|
||||||
, div
|
|
||||||
, h1
|
|
||||||
)
|
|
||||||
import Html.Attributes exposing (class)
|
|
||||||
import Html.Events exposing (onClick)
|
|
||||||
import RemoteData exposing (RemoteData(..))
|
|
||||||
import Route
|
|
||||||
import Search
|
|
||||||
exposing
|
|
||||||
( Details
|
|
||||||
, Model
|
|
||||||
, Msg(..)
|
|
||||||
, ResultItem
|
|
||||||
, SearchResult
|
|
||||||
, viewResult
|
|
||||||
)
|
|
||||||
import View.Components.SearchInput
|
|
||||||
exposing
|
|
||||||
( viewFlakes
|
|
||||||
, viewSearchInput
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
view :
|
|
||||||
{ toRoute : Route.SearchRoute
|
|
||||||
, categoryName : String
|
|
||||||
}
|
|
||||||
-> List (Html c)
|
|
||||||
-> Model a b
|
|
||||||
->
|
|
||||||
(String
|
|
||||||
-> Details
|
|
||||||
-> Maybe String
|
|
||||||
-> List (ResultItem a)
|
|
||||||
-> Html c
|
|
||||||
)
|
|
||||||
->
|
|
||||||
(Maybe String
|
|
||||||
-> SearchResult a b
|
|
||||||
-> List (Html c)
|
|
||||||
)
|
|
||||||
-> (Msg a b -> c)
|
|
||||||
-> Html c
|
|
||||||
view { toRoute, categoryName } title model viewSuccess viewBuckets outMsg =
|
|
||||||
let
|
|
||||||
resultStatus =
|
|
||||||
case model.result of
|
|
||||||
RemoteData.NotAsked ->
|
|
||||||
"not-asked"
|
|
||||||
|
|
||||||
RemoteData.Loading ->
|
|
||||||
"loading"
|
|
||||||
|
|
||||||
RemoteData.Success _ ->
|
|
||||||
"success"
|
|
||||||
|
|
||||||
RemoteData.Failure _ ->
|
|
||||||
"failure"
|
|
||||||
in
|
|
||||||
div
|
|
||||||
(List.append
|
|
||||||
[ class <| "search-page " ++ resultStatus ]
|
|
||||||
(if model.showSort then
|
|
||||||
[ onClick (outMsg ToggleSort) ]
|
|
||||||
|
|
||||||
else
|
|
||||||
[]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
[ h1 [] title
|
|
||||||
, viewSearchInput outMsg model.searchType model.query
|
|
||||||
, viewResult outMsg toRoute categoryName model viewSuccess viewBuckets <| viewFlakes outMsg model.channel model.searchType
|
|
||||||
]
|
|
|
@ -1,156 +0,0 @@
|
||||||
module View.Components.SearchInput exposing
|
|
||||||
( closeButton
|
|
||||||
, viewBucket
|
|
||||||
, viewFlakes
|
|
||||||
, viewSearchInput
|
|
||||||
)
|
|
||||||
|
|
||||||
import Html
|
|
||||||
exposing
|
|
||||||
( Html
|
|
||||||
, a
|
|
||||||
, button
|
|
||||||
, div
|
|
||||||
, form
|
|
||||||
, input
|
|
||||||
, li
|
|
||||||
, span
|
|
||||||
, text
|
|
||||||
, ul
|
|
||||||
)
|
|
||||||
import Html.Attributes
|
|
||||||
exposing
|
|
||||||
( autofocus
|
|
||||||
, class
|
|
||||||
, classList
|
|
||||||
, href
|
|
||||||
, id
|
|
||||||
, placeholder
|
|
||||||
, type_
|
|
||||||
, value
|
|
||||||
)
|
|
||||||
import Html.Events
|
|
||||||
exposing
|
|
||||||
( onClick
|
|
||||||
, onInput
|
|
||||||
, onSubmit
|
|
||||||
)
|
|
||||||
import Route
|
|
||||||
exposing
|
|
||||||
( SearchType
|
|
||||||
, allTypes
|
|
||||||
, searchTypeToString
|
|
||||||
, searchTypeToTitle
|
|
||||||
)
|
|
||||||
import Search exposing (Msg(..))
|
|
||||||
|
|
||||||
|
|
||||||
viewSearchInput :
|
|
||||||
(Msg a b -> c)
|
|
||||||
-> SearchType
|
|
||||||
-> Maybe String
|
|
||||||
-> Html c
|
|
||||||
viewSearchInput outMsg category searchQuery =
|
|
||||||
let
|
|
||||||
searchHint =
|
|
||||||
Maybe.withDefault "Packages and Options" <| Maybe.map (\_ -> searchTypeToString category) searchQuery
|
|
||||||
in
|
|
||||||
form
|
|
||||||
[ onSubmit (outMsg QueryInputSubmit)
|
|
||||||
, class "search-input"
|
|
||||||
]
|
|
||||||
[ div []
|
|
||||||
[ div []
|
|
||||||
[ input
|
|
||||||
[ type_ "text"
|
|
||||||
, id "search-query-input"
|
|
||||||
, autofocus True
|
|
||||||
, placeholder <| "Search for " ++ searchHint
|
|
||||||
, onInput (outMsg << QueryInput)
|
|
||||||
, value <| Maybe.withDefault "" searchQuery
|
|
||||||
]
|
|
||||||
[]
|
|
||||||
]
|
|
||||||
, button [ class "btn", type_ "submit" ]
|
|
||||||
[ text "Search" ]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
viewFlakes : (Msg a b -> msg) -> String -> SearchType -> List (Html msg)
|
|
||||||
viewFlakes outMsg _ selectedCategory =
|
|
||||||
[ li []
|
|
||||||
[ ul []
|
|
||||||
(List.map
|
|
||||||
(\category ->
|
|
||||||
li []
|
|
||||||
[ a
|
|
||||||
[ href "#"
|
|
||||||
, onClick <| outMsg (SubjectChange category)
|
|
||||||
, classList
|
|
||||||
[ ( "selected"
|
|
||||||
, category == selectedCategory
|
|
||||||
)
|
|
||||||
]
|
|
||||||
]
|
|
||||||
[ span [] [ text <| searchTypeToTitle category ]
|
|
||||||
, closeButton
|
|
||||||
]
|
|
||||||
]
|
|
||||||
)
|
|
||||||
allTypes
|
|
||||||
)
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
closeButton : Html a
|
|
||||||
closeButton =
|
|
||||||
span [] []
|
|
||||||
|
|
||||||
|
|
||||||
viewBucket :
|
|
||||||
String
|
|
||||||
-> List Search.AggregationsBucketItem
|
|
||||||
-> (String -> a)
|
|
||||||
-> List String
|
|
||||||
-> List (Html a)
|
|
||||||
-> List (Html a)
|
|
||||||
viewBucket title buckets searchMsgFor selectedBucket sets =
|
|
||||||
List.append
|
|
||||||
sets
|
|
||||||
(if List.isEmpty buckets then
|
|
||||||
[]
|
|
||||||
|
|
||||||
else
|
|
||||||
[ li []
|
|
||||||
[ ul []
|
|
||||||
(List.append
|
|
||||||
[ li [ class "header" ] [ text title ] ]
|
|
||||||
(List.map
|
|
||||||
(\bucket ->
|
|
||||||
li []
|
|
||||||
[ a
|
|
||||||
[ href "#"
|
|
||||||
, onClick <| searchMsgFor bucket.key
|
|
||||||
, classList
|
|
||||||
[ ( "selected"
|
|
||||||
, List.member bucket.key selectedBucket
|
|
||||||
)
|
|
||||||
]
|
|
||||||
]
|
|
||||||
[ span [] [ text bucket.key ]
|
|
||||||
, if List.member bucket.key selectedBucket then
|
|
||||||
closeButton
|
|
||||||
|
|
||||||
else
|
|
||||||
span [] [ span [ class "badge" ] [ text <| String.fromInt bucket.doc_count ] ]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
)
|
|
||||||
buckets
|
|
||||||
)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
]
|
|
||||||
)
|
|
Loading…
Reference in a new issue