Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
47e6572
fix(FeedVersionNavigator): reverse version sort; add retrieval method…
landonreed Mar 16, 2020
a279b5e
refactor(VersionRetrievalBadge): account for missing retrieval method
landonreed Mar 16, 2020
bc3a601
Merge branch 'dev' into mtc-20200310
landonreed Mar 16, 2020
4c4be61
refactor: fix lint
landonreed Mar 18, 2020
e8ec5f5
refactor: address PR comments
landonreed Mar 20, 2020
f1797a7
refactor: fix flow
landonreed Mar 26, 2020
18702dd
fix(gtfs.yml): add more currency types for fares
landonreed Apr 6, 2020
5fb9ec9
feat(GtfsPlusVersionSummary): Add GTFS+ validation issue details.
binh-dam-ibigroup Apr 10, 2020
f2ddd81
improvement(GtfsPlusVersionSummary): Remove top boder in issues cell.…
binh-dam-ibigroup Apr 10, 2020
ade917a
fix(GtfsPlusVersionSummary): Tame down changes
binh-dam-ibigroup Apr 10, 2020
4c3f49f
style(GtfsPlusVersionSummary): Revert some code layout.
binh-dam-ibigroup Apr 10, 2020
bd14749
fix(GtfsPlusVersionSummary): Address PR comments
binh-dam-ibigroup Apr 10, 2020
1820fc5
fix(getGtfsPlusSpec): Move sorting from GtfsPlusVersionSummary to get…
binh-dam-ibigroup Apr 13, 2020
5c65a19
style(GtfsPlusVersionSummary): Adjust code layout.
binh-dam-ibigroup Apr 13, 2020
e9a558c
Merge pull request #553 from ibi-group/mtc-gtfsplus
landonreed Apr 13, 2020
734517d
fix(gtfs+): change rider_category_id from Adult -> Regular
landonreed Mar 20, 2020
82e1adb
Merge branch 'dev' into mtc-20200310
landonreed May 22, 2020
388647c
feat(gtfs-transform): add feed transformation settings
landonreed May 27, 2020
17179a5
refactor(FeedVersionNavigator): remove unnecessary bad props checks
landonreed May 27, 2020
9572a69
Merge branch 'dev' into gtfs-transform
landonreed May 27, 2020
dc179b3
refactor: fix lint/flow
landonreed Jun 12, 2020
700ab3c
refactor(gtfs-transform): address MTC comments
landonreed Jun 16, 2020
6535049
add trip_short_name
philip-cline Jun 25, 2020
55e4a46
Merge branch 'dev' of https://github.com/ibi-group/datatools-ui into dev
philip-cline Jun 25, 2020
6918ce6
Add test in end-to-end for trip_short_name
philip-cline Jun 26, 2020
11d8cbe
Adding trip_short_name test to end-to-end
philip-cline Jun 26, 2020
16b7e53
removing blank lines in end-to-end.js
philip-cline Jun 26, 2020
13607e7
more whitespace formatting
philip-cline Jun 26, 2020
f7272fd
improvement(editor/selectors/timetable.js): Changed trip_short_name w…
philip-cline Jul 3, 2020
62c70db
refactor: fix flow typing
landonreed Jul 6, 2020
bccc6eb
refactor: fix flow def
landonreed Jul 6, 2020
3dd7760
refactor(gtfs-transform): move code into smaller files
landonreed Jul 6, 2020
b5dff34
refactor: update jsdoc
landonreed Jul 7, 2020
ee5e99d
refactor(gtfs-transform): add transformations indicator badge
landonreed Jul 7, 2020
d80572b
test(jest): update snapshots
landonreed Jul 7, 2020
c54ad48
Merge pull request #588 from ibi-group/add-trip_short_name
evansiroky Jul 8, 2020
9e148ff
fix(JobMonitor): replace conveyal support email w/ config value
landonreed Jul 8, 2020
5c5226b
refactor: address PR comments, add transform name tests
landonreed Jul 13, 2020
f6d8ab8
chore: fix lint
landonreed Jul 13, 2020
3d2c3c0
Merge pull request #579 from ibi-group/gtfs-transform
landonreed Jul 14, 2020
8e8ce1f
Merge pull request #591 from ibi-group/fix-support-email
landonreed Jul 14, 2020
c3cf9eb
Merge pull request #545 from ibi-group/mtc-20200310
landonreed Jul 15, 2020
70d4310
refactor(FeedVersionReport): remove title from non-date elements
landonreed Jul 15, 2020
81ceca9
build(deps): bump lodash from 4.17.13 to 4.17.19
dependabot[bot] Jul 16, 2020
7de38bc
Merge pull request #594 from ibi-group/fix-date-title
landonreed Jul 20, 2020
64badf1
docs(gtfs-transform): update docs
landonreed Jul 21, 2020
31c4fb2
docs: minor tweaks for transform docs
landonreed Jul 27, 2020
d6f291e
docs: fix bold -> backticks
landonreed Jul 27, 2020
447577b
Merge pull request #597 from ibi-group/update-docs-for-gtfs-transform
landonreed Jul 27, 2020
a99b828
build(deps): bump elliptic from 6.5.0 to 6.5.3
dependabot[bot] Jul 30, 2020
85b551f
Merge pull request #595 from ibi-group/dependabot/npm_and_yarn/lodash…
landonreed Jul 30, 2020
b21ae7e
build(deps): bump lodash from 4.17.4 to 4.17.19 in /scripts
dependabot[bot] Jul 30, 2020
85f4772
Merge pull request #601 from ibi-group/dependabot/npm_and_yarn/ellipt…
landonreed Jul 30, 2020
d851281
Merge pull request #596 from ibi-group/dependabot/npm_and_yarn/script…
landonreed Jul 30, 2020
348af46
build(deps-dev): bump auth0 from 2.18.0 to 2.27.1 in /scripts
dependabot[bot] Jul 30, 2020
1695a1e
Merge pull request #600 from ibi-group/dependabot/npm_and_yarn/script…
landonreed Aug 3, 2020
5b4f4fd
build(deps): bump extend from 3.0.1 to 3.0.2 in /scripts
dependabot[bot] Aug 3, 2020
269a6cb
Update index.md
Aug 3, 2020
646dfcf
Merge pull request #551 from ibi-group/add-more-currencies
landonreed Aug 10, 2020
b33c7ad
Merge pull request #602 from ibi-group/dependabot/npm_and_yarn/script…
landonreed Aug 11, 2020
872d61d
Merge pull request #603 from ibi-group/ritesh-warade-ibigroup-patch-1
landonreed Aug 11, 2020
606f964
fix(feedVersion): correctly show all modes in ServicePerModeChart
evansiroky Aug 28, 2020
67fd8bc
refactor: simplify code to check for modes with service
evansiroky Sep 2, 2020
99c19b1
Merge pull request #611 from ibi-group/service-hours-chart-fix
binh-dam-ibigroup Sep 9, 2020
e9ac9ff
test(e2e): wait longer for test user to get created
evansiroky Sep 22, 2020
a975c1d
ci: temporarily activate e2e tests
evansiroky Sep 22, 2020
ce5da1d
Revert "ci: temporarily activate e2e tests"
evansiroky Sep 22, 2020
71eb526
Merge pull request #613 from ibi-group/e2e-fixin
binh-dam-ibigroup Sep 29, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion __tests__/end-to-end.js
Original file line number Diff line number Diff line change
Expand Up @@ -885,7 +885,7 @@ describe('end-to-end', () => {
await click('[data-test-id="confirm-create-user-button"]')

// wait for user to be saved
await wait(2000, 'for user to be created')
await wait(30000, 'for user to be created')

// filter users
await filterUsers(testUserSlug)
Expand Down Expand Up @@ -2471,6 +2471,11 @@ describe('end-to-end', () => {
await page.keyboard.press('Tab')
await page.keyboard.press('Enter')

// trip short name
await page.keyboard.type('test-trip-short-name')
await page.keyboard.press('Tab')
await page.keyboard.press('Enter')

// Laurel Dr arrival
await page.keyboard.type('1234')
await page.keyboard.press('Tab')
Expand Down
2 changes: 2 additions & 0 deletions __tests__/test-utils/mock-data/manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ export const mockFeedWithVersion = {
retrievalMethod: 'MANUALLY_UPLOADED',
s3Url: null,
snapshotVersion: null,
transformRules: [],
url: 'http://mdtrip.org/googletransit/AnnapolisTransit/google_transit.zip',
user: null
}
Expand All @@ -160,6 +161,7 @@ export const mockFeedWithoutVersion = {
retrievalMethod: 'FETCHED_AUTOMATICALLY',
s3Url: null,
snapshotVersion: null,
transformRules: [],
url: null,
user: null
}
Expand Down
Binary file added docs/img/configure-feed-transformations.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/img/feed-transformation-summary.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# IBI Transit Data Tools
# IBI Transit Data Tools (TRANSIT-data-tools)

The IBI Transit Data Tools suite provides web-based tools for creating, managing, evaluating, and publishing transit data, specifically data stored in the General Transit Feed Specification (GTFS) format.

Expand Down
27 changes: 26 additions & 1 deletion docs/user/managing-projects-feeds.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,35 @@ Feed Versions are created from the main Feed Source profile page. There are thre

3. **Import From the GTFS Editor**: Select "From snapshot" from the `+ Create new version` dropdown. The list of snapshots should now be visible showing any available snapshots of the feed in the Editor. Select the desired snapshot by clicking the "Publish" button to publish the snapshot as a new version.

4. **Service Period Merge** (certain Data Tools configurations only): If a Feed Source has two or more Feed Versions, a new Feed Version can be created by merging two versions representing a transit agency's service over different time periods. While viewing a particular Feed Version, click `Merge with version` (underneath the map view) to select which past version you would like to merge with.

5. **Regional Merge**: For Projects that contain multiple Feed Sources across a region, it can be useful to merge multiple transit agencies together into a combined GTFS feed for the entire region. While viewing a Project's list of Feed Sources, click `Actions > Merge all` to produce a combined GTFS file for all Feed Sources.

**Note:** when uploading or fetching a feed, and the file being uploaded or fetched is not different from the latest version, no new Feed Version will be created.

## Loading Feed Versions into Editor
## Feed Transformations

Data Tools now supports **Feed Transformations**, which can apply a set of changes automatically to each new GTFS feed loaded into the system. This is especially helpful for applying repeatable changes to or inserting supplementary files into GTFS feeds that need to be enhanced. It provides a critical stopgap to improve GTFS coming out of systems that cannot be modified (e.g., scheduling software that has a rigid export format). The different transformation types currently supported are:

1. **Replace File From Version** - any file in an incoming GTFS (e.g., feed_info.txt) can be overwritten or inserted with a file extracted from a previously loaded feed version.

2. **Replace File From String** - any file in an incoming GTFS (e.g., feed_info.txt) can be overwritten or inserted with user-defined CSV data.

### Configuring Feed Transformations

Follow the steps below to configure Feed Transformations for an existing Feed Source:

1. Select a Feed Source and click `Settings > Feed Transformations`.
2. From here, click `Add transformation` to begin creating a new set of rules for incoming GTFS feeds. Your first ruleset will automatically apply to GTFS that is fetched automatically *and* manually uploaded, but this can be changed for each ruleset to apply to any of the retrieval methods listed in [Creating Feed Versions](#creating-feed-versions).
3. Click `Add step to transformation` to select a transformation type and fill in the required fields for each type. Multiple transformations can be specified and each will be applied to the incoming GTFS file in the order that they are defined.

![screenshot](../img/configure-feed-transformations.png)

### Viewing the Feed Transformation Summary

Once the Feed Transformations have all been configured, you can import a new GTFS file using one of the retrieval methods you have specified for your ruleset. Once the GTFS file has been processed, a summary of the transformations is available by hovering over the wrench icon that is visible in the Feed Version panel.

![screenshot](../img/feed-transformation-summary.png)


## Viewing and Managing Feed Versions
Expand Down
26 changes: 23 additions & 3 deletions gtfs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -629,9 +629,28 @@
inputType: DROPDOWN
bulkEditEnabled: true
options:
- value: 'USD'
- value: 'EUR'
- value: 'GBP'
- value: USD
text: US dollar (USD)
- value: AUD
text: Australian dollar (AUD)
- value: CAD
text: Canadian dollar (CAD)
- value: CHF
text: Swiss franc (CHF)
- value: CNH
text: Chinese renminbi (CNH)
- value: EUR
text: Euro (EUR)
- value: GBP
text: Pound sterling (GBP)
- value: JPY
text: Japanese yen (JPY)
- value: MXN
text: Mexican peso (MXN)
- value: NZD
text: New Zealand dollar (NZD)
- value: SEK
text: Swedish krona (SEK)
columnWidth: 12
helpContent: "The currency_type field defines the currency used to pay the fare. Please use the ISO 4217 alphabetical currency codes which can be found at the following URL:http://en.wikipedia.org/wiki/ISO_4217."
- name: "payment_method"
Expand Down Expand Up @@ -776,6 +795,7 @@

- id: scheduleexception
name: (none)
datatools: true
helpContent: Conveyal-specific table for classifying schedule exceptions.
fields:
- name: name
Expand Down
17 changes: 17 additions & 0 deletions i18n/english.yml
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,23 @@ components:
upload: Upload
versions: Versions
viewPublic: View public page
FeedTransformationDescriptions:
general:
fileDefined: below text
filePlaceholder: '[choose file]'
tablePlaceholder: '[choose table]'
table: table
version: version
versionPlaceholder: '[choose version]'
DeleteRecordsTransformation:
label: Delete records from %tablePlaceholder%
name: Delete records transformation
ReplaceFileFromStringTransformation:
label: Replace %tablePlaceholder% from %filePlaceholder%
name: Replace file from string transformation
ReplaceFileFromVersionTransformation:
label: Replace %tablePlaceholder% from %versionPlaceholder%
name: Replace file from version transformation
FeedVersionNavigator:
confirmDelete: Are you sure you want to delete this version? This cannot be undone.
confirmLoad: 'This will override all active GTFS Editor data for this Feed Source with the data from this version. If there is unsaved work in the Editor you want to keep, you must snapshot the current Editor data first. Are you sure you want to continue?'
Expand Down
4 changes: 2 additions & 2 deletions lib/common/actions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export function createVoidPayloadAction (type: string) {
return () => ({ type })
}

export function secureFetch (url: string, method: string = 'get', payload: any, raw: boolean = false, isJSON: boolean = true, actionOnFail: any): any {
export function secureFetch (url: string, method: string = 'get', payload?: any, raw: boolean = false, isJSON: boolean = true, actionOnFail?: string): any {
return function (dispatch: dispatchFn, getState: getStateFn) {
function consoleError (message) {
console.error(`Error making ${method} request to ${url}: `, message)
Expand Down Expand Up @@ -95,7 +95,7 @@ export function fetchGraphQL ({
}: {
errorMessage?: string,
query: string,
variables: any
variables?: {[key: string]: string | number | Array<string>}
}): any {
return function (dispatch: dispatchFn, getState: getStateFn) {
const body = {
Expand Down
17 changes: 11 additions & 6 deletions lib/common/components/JobMonitor.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {Link} from 'react-router'

import {removeRetiredJob} from '../../manager/actions/status'
import SidebarPopover from './SidebarPopover'
import {getConfigProperty} from '../util/config'

import type {ServerJob} from '../../types'
import type {JobStatusState} from '../../types/reducers'
Expand Down Expand Up @@ -136,6 +137,7 @@ class RetiredJob extends Component<{
render () {
const {job} = this.props
const path = this._getPathToObject()
const supportEmail = getConfigProperty('application.support_email')
return (
<li className='job-container'>
<div style={{ float: 'left' }}>
Expand Down Expand Up @@ -189,12 +191,15 @@ class RetiredJob extends Component<{
<Icon type='bug' /> Oh no! Looks like an error has occurred.
</span>
}>
<p>
To submit an error report email a screenshot of your browser
window, the following text (current URL and error details),
and a detailed description of the steps you followed
to <a href='mailto:support@conveyal.com'>support@conveyal.com</a>.
</p>
{supportEmail
? <p>
To submit an error report email a screenshot of your browser
window, the following text (current URL and error details),
and a detailed description of the steps you followed
to <a href={`mailto:${supportEmail}`}>{supportEmail}</a>.
</p>
: null
}
<p>{window.location.href}</p>
<span style={{whiteSpace: 'pre', fontSize: 'xx-small'}}>
{job.status.exceptionDetails}
Expand Down
16 changes: 16 additions & 0 deletions lib/common/constants/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// @flow

const SECURE: string = 'secure/'
export const API_PREFIX: string = `/api/manager/`
export const SECURE_API_PREFIX: string = `${API_PREFIX}${SECURE}`
Expand All @@ -9,3 +10,18 @@ export const DEFAULT_DESCRIPTION = 'A command center for managing, editing, vali
export const DEFAULT_LOGO = 'https://d2tyb7byn1fef9.cloudfront.net/ibi_group_black-512x512.png'
export const DEFAULT_LOGO_SMALL = 'https://d2tyb7byn1fef9.cloudfront.net/ibi_group-128x128.png'
export const DEFAULT_TITLE = 'Data Tools'

export const RETRIEVAL_METHODS = Object.freeze({
MANUALLY_UPLOADED: 'MANUALLY_UPLOADED',
FETCHED_AUTOMATICALLY: 'FETCHED_AUTOMATICALLY',
PRODUCED_IN_HOUSE: 'PRODUCED_IN_HOUSE',
SERVICE_PERIOD_MERGE: 'SERVICE_PERIOD_MERGE',
REGIONAL_MERGE: 'REGIONAL_MERGE',
VERSION_CLONE: 'VERSION_CLONE'
})

export const FEED_TRANSFORMATION_TYPES = Object.freeze({
DELETE_RECORDS: 'DeleteRecordsTransformation',
REPLACE_FILE_FROM_VERSION: 'ReplaceFileFromVersionTransformation',
REPLACE_FILE_FROM_STRING: 'ReplaceFileFromStringTransformation'
})
4 changes: 2 additions & 2 deletions lib/common/util/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export function getGtfsPlusSpec (): Array<GtfsSpecTable> {
const CONFIG: DataToolsConfig = window.DT_CONFIG
const GTFS_PLUS_SPEC = CONFIG.specifications.gtfsplus
if (!GTFS_PLUS_SPEC) throw new Error('GTFS+ yml configuration file is not defined!')
return GTFS_PLUS_SPEC
return GTFS_PLUS_SPEC.sort((table1, table2) => table1.name.localeCompare(table2.name))
}

/**
Expand All @@ -58,7 +58,7 @@ export function getComponentMessages (
return message
} else {
if (logWarning) console.warn(`Couldn't find message entry for ${componentName}.${path}`)
return `{${path}}`
return message || `{${path}}`
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions lib/editor/actions/trip.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ export function fetchTripsForCalendar (
) {
return function (dispatch: dispatchFn, getState: getStateFn) {
const namespace = getEditorNamespace(feedId, getState())
if (!namespace) throw new Error('Editor namespace is undefined!')
// This fetches patterns on the pattern_id field (rather than ID) because
// pattern_id is needed to join on the nested trips table
const query = `query ($namespace: String, $pattern_id: [String], $service_id: [String]) {
Expand Down Expand Up @@ -277,6 +278,7 @@ export function fetchCalendarTripCountsForPattern (
) {
return function (dispatch: dispatchFn, getState: getStateFn) {
const namespace = getEditorNamespace(feedId, getState())
if (!namespace) throw new Error('Editor namespace is undefined!')
// This fetches patterns on the pattern_id field (rather than ID) because
// pattern_id is needed to join on the nested trips table
const query = `query ($namespace: String, $pattern_id: String) {
Expand Down Expand Up @@ -304,6 +306,7 @@ export function fetchCalendarTripCountsForPattern (
export function fetchTripCounts (feedId: string) {
return function (dispatch: dispatchFn, getState: getStateFn) {
const namespace = getEditorNamespace(feedId, getState())
if (!namespace) throw new Error('Editor namespace is undefined!')
// This fetches patterns on the pattern_id field (rather than ID) because
// pattern_id is needed to join on the nested trips table
const query = `query ($namespace: String) {
Expand Down
7 changes: 7 additions & 0 deletions lib/editor/selectors/timetable.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ export const getTimetableColumns = createSelector(
key: 'tripHeadsign',
type: 'TEXT',
placeholder: 'Destination via Transfer Center'
},
{
name: 'Trip Short Name',
width: 120,
key: 'tripShortName',
type: 'TEXT',
placeholder: '801'
}
]
if (pattern && pattern.patternStops) {
Expand Down
20 changes: 15 additions & 5 deletions lib/gtfsplus/components/GtfsPlusVersionSummary.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
// @flow

import moment from 'moment'
import React, {Component} from 'react'
import {Panel, Row, Col, Table, Button, ButtonToolbar, Glyphicon, Alert} from 'react-bootstrap'
import {
Alert,
Button,
ButtonToolbar,
Col,
Glyphicon,
Panel,
Row,
Table
} from 'react-bootstrap'
import {browserHistory, Link} from 'react-router'
import moment from 'moment'

import {getGtfsPlusSpec} from '../../common/util/config'
import * as gtfsPlusActions from '../actions/gtfsplus'

import {getGtfsPlusSpec} from '../../common/util/config'
import type {Props as ContainerProps} from '../containers/ActiveGtfsPlusVersionSummary'
import type {GtfsPlusValidationIssue} from '../../types'
import type {GtfsPlusReducerState, ManagerUserState} from '../../types/reducers'

type Props = ContainerProps & {
Expand Down Expand Up @@ -51,7 +61,7 @@ export default class GtfsPlusVersionSummary extends Component<Props, State> {
return issuesForTable[tableId].length.toLocaleString()
}

_getTableLevelIssues = (tableId: string) => {
_getTableLevelIssues = (tableId: string): ?Array<GtfsPlusValidationIssue> => {
const {issuesForTable} = this.props
if (!issuesForTable) return null
if (!(tableId in issuesForTable)) return null
Expand Down Expand Up @@ -214,7 +224,7 @@ export default class GtfsPlusVersionSummary extends Component<Props, State> {
{tableLevelIssues.length} critical table issue(s):
<ul>
{tableLevelIssues.map((issue, i) =>
<li key={i}>{issue.description}</li>)}
<li key={i}>{issue.fieldName}: {issue.description}</li>)}
</ul>
</small>
: null
Expand Down
2 changes: 2 additions & 0 deletions lib/manager/actions/__tests__/__snapshots__/projects.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ Object {
"retrievalMethod": "MANUALLY_UPLOADED",
"s3Url": null,
"snapshotVersion": null,
"transformRules": Array [],
"url": "http://mdtrip.org/googletransit/AnnapolisTransit/google_transit.zip",
"user": null,
},
Expand Down Expand Up @@ -162,6 +163,7 @@ Object {
"retrievalMethod": "MANUALLY_UPLOADED",
"s3Url": null,
"snapshotVersion": null,
"transformRules": Array [],
"url": "http://mdtrip.org/googletransit/AnnapolisTransit/google_transit.zip",
"user": null,
},
Expand Down
Loading