goscript 0.0.42 → 0.0.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/compiler/analysis.go +87 -0
  2. package/compiler/assignment.go +6 -0
  3. package/compiler/compiler.go +85 -5
  4. package/compiler/composite-lit.go +17 -0
  5. package/compiler/decl.go +42 -20
  6. package/compiler/expr-call.go +37 -1
  7. package/compiler/expr-type.go +20 -0
  8. package/compiler/lit.go +4 -20
  9. package/compiler/spec-struct.go +3 -4
  10. package/compiler/spec-value.go +18 -1
  11. package/compiler/spec.go +15 -8
  12. package/compiler/stmt-range.go +1 -1
  13. package/compiler/type-assert.go +4 -4
  14. package/compiler/type.go +63 -5
  15. package/dist/gs/builtin/map.d.ts +4 -4
  16. package/dist/gs/builtin/map.js +6 -3
  17. package/dist/gs/builtin/map.js.map +1 -1
  18. package/dist/gs/builtin/slice.d.ts +7 -0
  19. package/dist/gs/builtin/slice.js +12 -0
  20. package/dist/gs/builtin/slice.js.map +1 -1
  21. package/dist/gs/builtin/type.js +8 -85
  22. package/dist/gs/builtin/type.js.map +1 -1
  23. package/dist/gs/fmt/fmt.d.ts +22 -21
  24. package/dist/gs/fmt/fmt.js +12 -12
  25. package/dist/gs/fmt/fmt.js.map +1 -1
  26. package/dist/gs/fmt/index.d.ts +2 -1
  27. package/dist/gs/fmt/index.js.map +1 -1
  28. package/dist/gs/internal/testlog/index.d.ts +1 -0
  29. package/dist/gs/internal/testlog/index.js +5 -0
  30. package/dist/gs/internal/testlog/index.js.map +1 -0
  31. package/dist/gs/io/io.d.ts +13 -13
  32. package/dist/gs/io/io.js +31 -21
  33. package/dist/gs/io/io.js.map +1 -1
  34. package/dist/gs/maps/iter.gs.d.ts +7 -0
  35. package/dist/gs/maps/iter.gs.js +65 -0
  36. package/dist/gs/maps/iter.gs.js.map +1 -0
  37. package/dist/gs/maps/maps.gs.d.ts +7 -0
  38. package/dist/gs/maps/maps.gs.js +79 -0
  39. package/dist/gs/maps/maps.gs.js.map +1 -0
  40. package/dist/gs/os/error.gs.d.ts +1 -1
  41. package/dist/gs/os/error.gs.js +1 -1
  42. package/dist/gs/os/error.gs.js.map +1 -1
  43. package/dist/gs/path/filepath/match.d.ts +4 -3
  44. package/dist/gs/path/filepath/match.js +2 -2
  45. package/dist/gs/path/filepath/match.js.map +1 -1
  46. package/dist/gs/path/filepath/path.d.ts +2 -2
  47. package/dist/gs/path/filepath/path.js +3 -3
  48. package/dist/gs/path/filepath/path.js.map +1 -1
  49. package/dist/gs/reflect/abi.d.ts +59 -0
  50. package/dist/gs/reflect/abi.gs.d.ts +59 -0
  51. package/dist/gs/reflect/abi.gs.js +79 -0
  52. package/dist/gs/reflect/abi.gs.js.map +1 -0
  53. package/dist/gs/reflect/abi.js +79 -0
  54. package/dist/gs/reflect/abi.js.map +1 -0
  55. package/dist/gs/reflect/badlinkname.d.ts +52 -0
  56. package/dist/gs/reflect/badlinkname.gs.d.ts +52 -0
  57. package/dist/gs/reflect/badlinkname.gs.js +72 -0
  58. package/dist/gs/reflect/badlinkname.gs.js.map +1 -0
  59. package/dist/gs/reflect/badlinkname.js +72 -0
  60. package/dist/gs/reflect/badlinkname.js.map +1 -0
  61. package/dist/gs/reflect/deepequal.gs.d.ts +25 -0
  62. package/dist/gs/reflect/deepequal.gs.js +308 -0
  63. package/dist/gs/reflect/deepequal.gs.js.map +1 -0
  64. package/dist/gs/reflect/float32reg_generic.gs.d.ts +2 -0
  65. package/dist/gs/reflect/float32reg_generic.gs.js +10 -0
  66. package/dist/gs/reflect/float32reg_generic.gs.js.map +1 -0
  67. package/dist/gs/reflect/index.gs.d.ts +1 -0
  68. package/dist/gs/reflect/index.gs.js +3 -0
  69. package/dist/gs/reflect/index.gs.js.map +1 -0
  70. package/dist/gs/reflect/iter.gs.d.ts +3 -0
  71. package/dist/gs/reflect/iter.gs.js +24 -0
  72. package/dist/gs/reflect/iter.gs.js.map +1 -0
  73. package/dist/gs/reflect/makefunc.gs.d.ts +34 -0
  74. package/dist/gs/reflect/makefunc.gs.js +288 -0
  75. package/dist/gs/reflect/makefunc.gs.js.map +1 -0
  76. package/dist/gs/reflect/map_swiss.gs.d.ts +14 -0
  77. package/dist/gs/reflect/map_swiss.gs.js +70 -0
  78. package/dist/gs/reflect/map_swiss.gs.js.map +1 -0
  79. package/dist/gs/reflect/reflect.gs.d.ts +132 -0
  80. package/dist/gs/reflect/reflect.gs.js +437 -0
  81. package/dist/gs/reflect/reflect.gs.js.map +1 -0
  82. package/dist/gs/reflect/swapper.gs.d.ts +1 -0
  83. package/dist/gs/reflect/swapper.gs.js +32 -0
  84. package/dist/gs/reflect/swapper.gs.js.map +1 -0
  85. package/dist/gs/reflect/type.gs.d.ts +4 -0
  86. package/dist/gs/reflect/type.gs.js +21 -0
  87. package/dist/gs/reflect/type.gs.js.map +1 -0
  88. package/dist/gs/reflect/value.gs.d.ts +4 -0
  89. package/dist/gs/reflect/value.gs.js +12 -0
  90. package/dist/gs/reflect/value.gs.js.map +1 -0
  91. package/dist/gs/reflect/visiblefields.gs.d.ts +3 -0
  92. package/dist/gs/reflect/visiblefields.gs.js +123 -0
  93. package/dist/gs/reflect/visiblefields.gs.js.map +1 -0
  94. package/dist/gs/strings/reader.d.ts +1 -1
  95. package/dist/gs/strings/reader.js.map +1 -1
  96. package/dist/gs/stringslite/index.d.ts +1 -0
  97. package/dist/gs/stringslite/index.js +2 -0
  98. package/dist/gs/stringslite/index.js.map +1 -0
  99. package/dist/gs/stringslite/strings.d.ts +11 -0
  100. package/dist/gs/stringslite/strings.js +67 -0
  101. package/dist/gs/stringslite/strings.js.map +1 -0
  102. package/dist/gs/time/time.d.ts +69 -0
  103. package/dist/gs/time/time.js +350 -0
  104. package/dist/gs/time/time.js.map +1 -1
  105. package/gs/builtin/map.ts +12 -8
  106. package/gs/builtin/slice.ts +13 -0
  107. package/gs/builtin/type.ts +8 -116
  108. package/gs/fmt/fmt.ts +33 -33
  109. package/gs/fmt/index.ts +4 -0
  110. package/gs/io/io.ts +47 -39
  111. package/gs/os/error.gs.ts +1 -1
  112. package/gs/path/filepath/match.ts +4 -4
  113. package/gs/path/filepath/path.ts +3 -3
  114. package/gs/strings/reader.ts +1 -1
  115. package/gs/time/time.ts +403 -0
  116. package/package.json +1 -1
package/gs/time/time.ts CHANGED
@@ -22,6 +22,106 @@ export class Time {
22
22
  return new Time(this._date, this._nsec, this._monotonic, this._location)
23
23
  }
24
24
 
25
+ // Unix returns t as a Unix time, the number of seconds elapsed since January 1, 1970 UTC
26
+ public Unix(): number {
27
+ return Math.floor(this._date.getTime() / 1000)
28
+ }
29
+
30
+ // UnixMilli returns t as a Unix time, the number of milliseconds elapsed since January 1, 1970 UTC
31
+ public UnixMilli(): number {
32
+ return this._date.getTime()
33
+ }
34
+
35
+ // UnixMicro returns t as a Unix time, the number of microseconds elapsed since January 1, 1970 UTC
36
+ public UnixMicro(): number {
37
+ return Math.floor(this._date.getTime() * 1000) + Math.floor(this._nsec / 1000)
38
+ }
39
+
40
+ // UnixNano returns t as a Unix time, the number of nanoseconds elapsed since January 1, 1970 UTC
41
+ public UnixNano(): number {
42
+ return this._date.getTime() * 1000000 + this._nsec
43
+ }
44
+
45
+ // Weekday returns the day of the week specified by t
46
+ public Weekday(): WeekdayValue {
47
+ if (this._location.offsetSeconds !== undefined) {
48
+ const offsetMs = this._location.offsetSeconds * 1000
49
+ const adjustedTime = new globalThis.Date(this._date.getTime() + offsetMs)
50
+ return new WeekdayValue(adjustedTime.getUTCDay() as Weekday)
51
+ }
52
+ return new WeekdayValue(this._date.getDay() as Weekday)
53
+ }
54
+
55
+ // Day returns the day of the month specified by t
56
+ public Day(): number {
57
+ if (this._location.offsetSeconds !== undefined) {
58
+ const offsetMs = this._location.offsetSeconds * 1000
59
+ const adjustedTime = new globalThis.Date(this._date.getTime() + offsetMs)
60
+ return adjustedTime.getUTCDate()
61
+ }
62
+ return this._date.getDate()
63
+ }
64
+
65
+ // Month returns the month of the year specified by t
66
+ public Month(): Month {
67
+ if (this._location.offsetSeconds !== undefined) {
68
+ const offsetMs = this._location.offsetSeconds * 1000
69
+ const adjustedTime = new globalThis.Date(this._date.getTime() + offsetMs)
70
+ return (adjustedTime.getUTCMonth() + 1) as Month
71
+ }
72
+ return (this._date.getMonth() + 1) as Month
73
+ }
74
+
75
+ // Year returns the year in which t occurs
76
+ public Year(): number {
77
+ if (this._location.offsetSeconds !== undefined) {
78
+ const offsetMs = this._location.offsetSeconds * 1000
79
+ const adjustedTime = new globalThis.Date(this._date.getTime() + offsetMs)
80
+ return adjustedTime.getUTCFullYear()
81
+ }
82
+ return this._date.getFullYear()
83
+ }
84
+
85
+ // Hour returns the hour within the day specified by t, in the range [0, 23]
86
+ public Hour(): number {
87
+ if (this._location.offsetSeconds !== undefined) {
88
+ const offsetMs = this._location.offsetSeconds * 1000
89
+ const adjustedTime = new globalThis.Date(this._date.getTime() + offsetMs)
90
+ return adjustedTime.getUTCHours()
91
+ }
92
+ return this._date.getHours()
93
+ }
94
+
95
+ // Minute returns the minute offset within the hour specified by t, in the range [0, 59]
96
+ public Minute(): number {
97
+ if (this._location.offsetSeconds !== undefined) {
98
+ const offsetMs = this._location.offsetSeconds * 1000
99
+ const adjustedTime = new globalThis.Date(this._date.getTime() + offsetMs)
100
+ return adjustedTime.getUTCMinutes()
101
+ }
102
+ return this._date.getMinutes()
103
+ }
104
+
105
+ // Second returns the second offset within the minute specified by t, in the range [0, 59]
106
+ public Second(): number {
107
+ if (this._location.offsetSeconds !== undefined) {
108
+ const offsetMs = this._location.offsetSeconds * 1000
109
+ const adjustedTime = new globalThis.Date(this._date.getTime() + offsetMs)
110
+ return adjustedTime.getUTCSeconds()
111
+ }
112
+ return this._date.getSeconds()
113
+ }
114
+
115
+ // Nanosecond returns the nanosecond offset within the second specified by t, in the range [0, 999999999]
116
+ public Nanosecond(): number {
117
+ return this._nsec
118
+ }
119
+
120
+ // Location returns the time zone information associated with t
121
+ public Location(): Location {
122
+ return this._location
123
+ }
124
+
25
125
  // Format returns a textual representation of the time value formatted according to the layout
26
126
  public Format(layout: string): string {
27
127
  // Implementation of Go's time formatting based on reference time:
@@ -520,6 +620,11 @@ export class Location {
520
620
  public get offsetSeconds(): number | undefined {
521
621
  return this._offsetSeconds
522
622
  }
623
+
624
+ // String returns a descriptive name for the time zone information
625
+ public String(): string {
626
+ return this._name
627
+ }
523
628
  }
524
629
 
525
630
  // Month represents a month of the year
@@ -538,6 +643,149 @@ export enum Month {
538
643
  December = 12,
539
644
  }
540
645
 
646
+ // Weekday represents a day of the week
647
+ export enum Weekday {
648
+ Sunday = 0,
649
+ Monday = 1,
650
+ Tuesday = 2,
651
+ Wednesday = 3,
652
+ Thursday = 4,
653
+ Friday = 5,
654
+ Saturday = 6,
655
+ }
656
+
657
+ // WeekdayString returns the string representation of a Weekday
658
+ export function WeekdayString(w: Weekday): string {
659
+ const names = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
660
+ return names[w] || 'Unknown'
661
+ }
662
+
663
+ // WeekdayValue wraps a Weekday enum value and provides methods
664
+ export class WeekdayValue {
665
+ private _value: Weekday
666
+
667
+ constructor(value: Weekday) {
668
+ this._value = value
669
+ }
670
+
671
+ public valueOf(): number {
672
+ return this._value
673
+ }
674
+
675
+ public String(): string {
676
+ return WeekdayString(this._value)
677
+ }
678
+ }
679
+
680
+ // ParseError describes a problem parsing a time string
681
+ export class ParseError extends Error {
682
+ public layout: string
683
+ public value: string
684
+ public layoutElem: string
685
+ public valueElem: string
686
+ public message: string
687
+
688
+ constructor(
689
+ layout: string,
690
+ value: string,
691
+ layoutElem: string,
692
+ valueElem: string,
693
+ message: string,
694
+ ) {
695
+ super(message)
696
+ this.layout = layout
697
+ this.value = value
698
+ this.layoutElem = layoutElem
699
+ this.valueElem = valueElem
700
+ this.message = message
701
+ this.name = 'ParseError'
702
+ }
703
+ }
704
+
705
+ // Timer represents a single event timer
706
+ export class Timer {
707
+ private _timeout: NodeJS.Timeout | number
708
+ private _duration: Duration
709
+ private _callback?: () => void
710
+
711
+ constructor(duration: Duration, callback?: () => void) {
712
+ this._duration = duration
713
+ this._callback = callback
714
+ const ms = duration.valueOf() / 1000000 // Convert nanoseconds to milliseconds
715
+
716
+ if (callback) {
717
+ this._timeout = setTimeout(callback, ms)
718
+ } else {
719
+ this._timeout = setTimeout(() => {}, ms)
720
+ }
721
+ }
722
+
723
+ // Stop prevents the Timer from firing
724
+ public Stop(): boolean {
725
+ if (typeof this._timeout === 'number') {
726
+ clearTimeout(this._timeout)
727
+ } else {
728
+ clearTimeout(this._timeout)
729
+ }
730
+ return true
731
+ }
732
+
733
+ // Reset changes the timer to expire after duration d
734
+ public Reset(d: Duration): boolean {
735
+ this.Stop()
736
+ const ms = d.valueOf() / 1000000
737
+ if (this._callback) {
738
+ this._timeout = setTimeout(this._callback, ms)
739
+ } else {
740
+ this._timeout = setTimeout(() => {}, ms)
741
+ }
742
+ return true
743
+ }
744
+ }
745
+
746
+ // Ticker holds a channel that delivers ticks at intervals
747
+ export class Ticker {
748
+ private _interval: NodeJS.Timeout | number
749
+ private _duration: Duration
750
+ private _stopped: boolean = false
751
+
752
+ constructor(duration: Duration) {
753
+ this._duration = duration
754
+ const ms = duration.valueOf() / 1000000 // Convert nanoseconds to milliseconds
755
+ this._interval = setInterval(() => {}, ms)
756
+ }
757
+
758
+ // Stop turns off a ticker
759
+ public Stop(): void {
760
+ this._stopped = true
761
+ if (typeof this._interval === 'number') {
762
+ clearInterval(this._interval)
763
+ } else {
764
+ clearInterval(this._interval)
765
+ }
766
+ }
767
+
768
+ // Reset stops a ticker and resets its period to the specified duration
769
+ public Reset(d: Duration): void {
770
+ this.Stop()
771
+ this._stopped = false
772
+ this._duration = d
773
+ const ms = d.valueOf() / 1000000
774
+ this._interval = setInterval(() => {}, ms)
775
+ }
776
+
777
+ // Channel returns an async iterator that yields time values
778
+ public async* Channel(): AsyncIterableIterator<Time> {
779
+ const ms = this._duration.valueOf() / 1000000
780
+ while (!this._stopped) {
781
+ await new Promise(resolve => setTimeout(resolve, ms))
782
+ if (!this._stopped) {
783
+ yield Now()
784
+ }
785
+ }
786
+ }
787
+ }
788
+
541
789
  // Now returns the current local time with monotonic clock reading
542
790
  export function Now(): Time {
543
791
  const date = new globalThis.Date()
@@ -640,3 +888,158 @@ export const DateTime = '2006-01-02 15:04:05'
640
888
  export const Layout = "01/02 03:04:05PM '06 -0700"
641
889
  export const RFC3339 = '2006-01-02T15:04:05Z07:00'
642
890
  export const Kitchen = '3:04PM'
891
+
892
+ // Unix returns the local Time corresponding to the given Unix time,
893
+ // sec seconds and nsec nanoseconds since January 1, 1970 UTC
894
+ export function Unix(sec: number, nsec: number = 0): Time {
895
+ const ms = sec * 1000 + Math.floor(nsec / 1000000)
896
+ const remainingNsec = nsec % 1000000
897
+ return new Time(new globalThis.Date(ms), remainingNsec, undefined, UTC)
898
+ }
899
+
900
+ // UnixMilli returns the local Time corresponding to the given Unix time,
901
+ // msec milliseconds since January 1, 1970 UTC
902
+ export function UnixMilli(msec: number): Time {
903
+ return new Time(new globalThis.Date(msec), 0, undefined, UTC)
904
+ }
905
+
906
+ // UnixMicro returns the local Time corresponding to the given Unix time,
907
+ // usec microseconds since January 1, 1970 UTC
908
+ export function UnixMicro(usec: number): Time {
909
+ const ms = Math.floor(usec / 1000)
910
+ const nsec = (usec % 1000) * 1000
911
+ return new Time(new globalThis.Date(ms), nsec, undefined, UTC)
912
+ }
913
+
914
+ // UnixNano returns the local Time corresponding to the given Unix time,
915
+ // nsec nanoseconds since January 1, 1970 UTC
916
+ export function UnixNano(nsec: number): Time {
917
+ const ms = Math.floor(nsec / 1000000)
918
+ const remainingNsec = nsec % 1000000
919
+ return new Time(new globalThis.Date(ms), remainingNsec, undefined, UTC)
920
+ }
921
+
922
+ // ParseDuration parses a duration string
923
+ // A duration string is a possibly signed sequence of decimal numbers,
924
+ // each with optional fraction and a unit suffix
925
+ export function ParseDuration(s: string): Duration {
926
+ const regex = /^([+-]?)(\d+(?:\.\d+)?)(ns|us|µs|ms|s|m|h)$/
927
+ const match = s.match(regex)
928
+
929
+ if (!match) {
930
+ throw new Error(`time: invalid duration "${s}"`)
931
+ }
932
+
933
+ const [, sign, valueStr, unit] = match
934
+ let value = parseFloat(valueStr)
935
+ if (sign === '-') value = -value
936
+
937
+ let nanoseconds: number
938
+ switch (unit) {
939
+ case 'ns':
940
+ nanoseconds = value
941
+ break
942
+ case 'us':
943
+ case 'µs':
944
+ nanoseconds = value * 1000
945
+ break
946
+ case 'ms':
947
+ nanoseconds = value * 1000000
948
+ break
949
+ case 's':
950
+ nanoseconds = value * 1000000000
951
+ break
952
+ case 'm':
953
+ nanoseconds = value * 60000000000
954
+ break
955
+ case 'h':
956
+ nanoseconds = value * 3600000000000
957
+ break
958
+ default:
959
+ throw new Error(`time: unknown unit "${unit}" in duration "${s}"`)
960
+ }
961
+
962
+ return new Duration(Math.floor(nanoseconds))
963
+ }
964
+
965
+ // Parse parses a formatted string and returns the time value it represents
966
+ export function Parse(layout: string, value: string): Time {
967
+ return ParseInLocation(layout, value, UTC)
968
+ }
969
+
970
+ // ParseInLocation is like Parse but differs in two important ways
971
+ export function ParseInLocation(layout: string, value: string, loc: Location): Time {
972
+ // This is a simplified implementation
973
+ // A full implementation would need to parse according to the layout format
974
+
975
+ // Handle common layouts
976
+ if (layout === RFC3339 || layout === '2006-01-02T15:04:05Z07:00') {
977
+ const date = new globalThis.Date(value)
978
+ if (isNaN(date.getTime())) {
979
+ throw new ParseError(layout, value, '', '', `parsing time "${value}" as "${layout}": cannot parse`)
980
+ }
981
+ return new Time(date, 0, undefined, loc)
982
+ }
983
+
984
+ if (layout === DateTime || layout === '2006-01-02 15:04:05') {
985
+ const date = new globalThis.Date(value)
986
+ if (isNaN(date.getTime())) {
987
+ throw new ParseError(layout, value, '', '', `parsing time "${value}" as "${layout}": cannot parse`)
988
+ }
989
+ return new Time(date, 0, undefined, loc)
990
+ }
991
+
992
+ // Fallback to standard Date parsing
993
+ const date = new globalThis.Date(value)
994
+ if (isNaN(date.getTime())) {
995
+ throw new ParseError(layout, value, '', '', `parsing time "${value}" as "${layout}": cannot parse`)
996
+ }
997
+ return new Time(date, 0, undefined, loc)
998
+ }
999
+
1000
+ // After waits for the duration to elapse and then returns the current time
1001
+ export async function After(d: Duration): Promise<Time> {
1002
+ await Sleep(d)
1003
+ return Now()
1004
+ }
1005
+
1006
+ // AfterFunc waits for the duration to elapse and then calls f
1007
+ export function AfterFunc(d: Duration, f: () => void): Timer {
1008
+ return new Timer(d, f)
1009
+ }
1010
+
1011
+ // NewTimer creates a new Timer that will fire after the given duration
1012
+ export function NewTimer(d: Duration): Timer {
1013
+ return new Timer(d)
1014
+ }
1015
+
1016
+ // NewTicker returns a new Ticker containing a channel that will send the current time
1017
+ export function NewTicker(d: Duration): Ticker {
1018
+ return new Ticker(d)
1019
+ }
1020
+
1021
+ // Tick is a convenience wrapper for NewTicker providing access to the ticking channel only
1022
+ export function Tick(d: Duration): AsyncIterableIterator<Time> {
1023
+ return new Ticker(d).Channel()
1024
+ }
1025
+
1026
+ // LoadLocation returns the Location with the given name
1027
+ // This is a simplified implementation that only supports UTC and Local
1028
+ export function LoadLocation(name: string): Location {
1029
+ switch (name) {
1030
+ case 'UTC':
1031
+ return UTC
1032
+ case 'Local':
1033
+ // Return a location that uses local time (no fixed offset)
1034
+ return new Location('Local')
1035
+ default:
1036
+ throw new Error(`time: unknown time zone ${name}`)
1037
+ }
1038
+ }
1039
+
1040
+ // LoadLocationFromTZData returns a Location with the given name
1041
+ // This is a simplified implementation
1042
+ export function LoadLocationFromTZData(name: string, _data: Uint8Array): Location {
1043
+ // In a real implementation, this would parse the timezone data
1044
+ return new Location(name)
1045
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "goscript",
3
3
  "description": "Go to TypeScript transpiler",
4
- "version": "0.0.42",
4
+ "version": "0.0.44",
5
5
  "author": {
6
6
  "name": "Aperture Robotics LLC.",
7
7
  "email": "support@aperture.us",