Implement Haskell-like primes iterator in Rust - haskell

I am trying to implement a Rust iterator similar to the following Haskell code:
primes :: [Integer]
primes = nextPrime [2..]
where
nextPrime (x:xs) = x : nextPrime (filter (notDivBy x) xs)
notDivBy a x = a `mod` x /= 0
My attempt so far (playground):
// as pointed out in a comment this can simply return Primes and not use Box::new
fn primes() -> Box<dyn Iterator<Item = usize>> {
Box::new(Primes::new())
}
struct Primes {
nums: Box<dyn Iterator<Item = usize>>,
}
impl Primes {
fn new() -> Self {
Primes { nums : Box::new(2..) }
}
}
impl Iterator for Primes {
type Item = usize;
fn next(&mut self) -> Option<usize> {
let prime = self.nums.next().unwrap();
self.nums = Box::new(self.nums.filter(move |&n|!divides(prime, n)));
//use std::borrow::BorrowMut;
//*self.nums.borrow_mut() = self.nums.filter(move |&n|!divides(prime, n));
Some(prime)
}
}
pub fn divides(d: usize, n: usize) -> bool {
n % d == 0
}
Unfortunately this runs into:
error[E0507]: cannot move out of `self.nums` which is behind a mutable reference
--> src/lib.rs:22:30
|
22 | self.nums = Box::new(self.nums.filter(move |&n| !divides(prime, n)));
| ^^^^^^^^^ move occurs because `self.nums` has type `Box<dyn Iterator<Item = usize>>`, which does not implement the `Copy` trait
For more information about this error, try `rustc --explain E0507`.
Or if you uncomment the alternative borrow_mut code:
error[E0277]: the trait bound `Box<(dyn Iterator<Item = usize> + 'static)>: BorrowMut<Filter<Box<dyn Iterator<Item = usize>>, [closure#src/lib.rs:24:52: 24:79]>>` is not satisfied
--> src/lib.rs:24:20
|
24 | *self.nums.borrow_mut() = self.nums.filter(move |&n|!divides(prime, n));
| ^^^^^^^^^^ the trait `BorrowMut<Filter<Box<dyn Iterator<Item = usize>>, [closure#src/lib.rs:24:52: 24:79]>>` is not implemented for `Box<(dyn Iterator<Item = usize> + 'static)>`
|
= help: the following implementations were found:
<Box<T, A> as BorrowMut<T>>
Frankly I am not even sure which of these two is closer to working.

I think you can cache the discovered primes:
fn primes() -> Primes {
Primes::new()
}
struct Primes {
nums: Box<dyn Iterator<Item = usize>>,
cache: Vec<usize>,
}
impl Primes {
fn new() -> Self {
Primes {
nums: Box::new(2..),
cache: Vec::new(),
}
}
}
impl Iterator for Primes {
type Item = usize;
fn next(&mut self) -> Option<usize> {
loop {
let num = self.nums.next().unwrap();
if self
.cache
.iter()
.take_while(|&&n| n*n <= num)
.all(|&p| !divides(p, num))
{
// we found a prime!
self.cache.push(num);
return Some(num);
}
}
}
}
pub fn divides(d: usize, n: usize) -> bool {
n % d == 0
}
fn main() {
println!("Primes: {:?}", primes().take(10).collect::<Vec<_>>());
}
Playground

I'm not really expert in Rust, but one (ugly) option is to replace self.nums with a dummy iterator so to be able to move the previous value.
fn next(&mut self) -> Option<usize> {
let prime = self.nums.next().unwrap();
// Ugly replacement with a dummy iterator value
let rest = std::mem::replace(&mut self.nums, Box::new(0..));
self.nums = Box::new(rest.filter(move |&n|!divides(prime, n)));
Some(prime)
}
This could be cleaner if we used an Option wrapper so that we can use None as the dummy value.

I finally figured out (with the help of the other answers) how to fix cannot move out of self.nums which is behind a mutable reference. The trick is to use &mut self.nums (and get rid of the Box).
fn primes() -> Primes {
Primes::new()
}
pub struct Primes {
nums: std::ops::RangeFrom<usize>,
cache: Vec<usize>,
}
impl Primes {
fn new() -> Self {
Primes {
nums: 2..,
cache: Vec::new(),
}
}
}
impl Iterator for Primes {
type Item = usize;
fn next(&mut self) -> Option<usize> {
let next_prime = (&mut self.nums)
.filter(|&n| {
self.cache
.iter()
.take_while(|&p| p * p <= n)
.all(|&p| !divides(p, n))
})
.next()
.unwrap();
self.cache.push(next_prime);
return Some(next_prime);
}
}
pub fn divides(d: usize, n: usize) -> bool {
n % d == 0
}
fn main() {
println!("Primes: {:?}", primes().take(10).collect::<Vec<_>>());
}
playground

Related

Implement mutable enumeration method on 2D grid

I have a mostly working implementation of a 2D grid in rust:
use itertools::Itertools;
#[derive(Debug)]
pub struct Grid<T> {
width: usize,
height: usize,
items: Vec<T>,
}
impl<T> Grid<T> {
pub fn new(width: usize, height: usize, initializer: impl Fn() -> T) -> Self {
Self {
width,
height,
items: (0..height * width).map(|_| initializer()).collect(),
}
}
pub fn width(&self) -> usize {
self.width
}
pub fn height(&self) -> usize {
self.height
}
pub fn size(&self) -> usize {
self.width * self.height
}
pub fn get(&self, x: usize, y: usize) -> Result<&T, &str> {
if self.on_grid(x as isize, y as isize) {
Ok(&self.items[self.coordinate_to_index(x, y)])
} else {
Err("coordinate not on grid")
}
}
pub fn get_mut(&mut self, x: usize, y: usize) -> Result<&mut T, &str> {
if self.on_grid(x as isize, y as isize) {
let index = self.coordinate_to_index(x, y);
Ok(&mut self.items[index])
} else {
Err("coordinate not on grid")
}
}
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.items.iter()
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
self.items.iter_mut()
}
pub fn enumerate(&self) -> impl Iterator<Item = (usize, usize, &T)> {
self.items.iter().enumerate().map(|(index, item)| {
let (x, y) = self.index_to_coordinate(index);
(x, y, item)
})
}
pub fn enumerate_mut(&mut self) -> impl Iterator<Item = (usize, usize, &mut T)> {
self.items.iter_mut().enumerate().map(move |(index, item)| {
let (x, y) = self.index_to_coordinate(index);
(x, y, item)
})
}
pub fn neighbors(&self, x: usize, y: usize) -> impl Iterator<Item = (usize, usize, &T)> {
self.neighbor_indices(x, y)
.map(|(x, y)| (x, y, &self.items[self.coordinate_to_index(x, y)]))
}
fn coordinate_to_index(&self, x: usize, y: usize) -> usize {
y * self.width + x
}
fn index_to_coordinate(&self, index: usize) -> (usize, usize) {
let x = index % self.width;
let y = (index - x) / self.width;
(x, y)
}
fn neighbor_indices(&self, x: usize, y: usize) -> impl Iterator<Item = (usize, usize)> + '_ {
neighbor_offsets(2)
.map(move |item| (x as isize + item[0], y as isize + item[1]))
.filter(|&(x, y)| self.on_grid(x, y))
.map(|(dx, dy)| (dx as usize, dy as usize))
}
fn on_grid(&self, x: isize, y: isize) -> bool {
0 <= x && x < self.width as isize && 0 <= y && y < self.height as isize
}
}
fn neighbor_offsets(dimension: usize) -> impl Iterator<Item = Vec<isize>> {
(-1..1)
.map(|index| index as isize)
.combinations_with_replacement(dimension)
// skip zero offset
.filter(|items| !items.iter().all(|&item| item == 0))
}
Cargo.toml
[package]
name = "grid"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
itertools = "*"
However, with enumerate_mut() the compilation currently fails with
$ cargo build
Compiling either v1.8.0
Compiling itertools v0.10.5
Compiling grid v0.1.0 (/home/neumann/Projekte/grid)
error[E0505]: cannot move out of `self` because it is borrowed
--> src/lib.rs:64:47
|
63 | pub fn enumerate_mut(&mut self) -> impl Iterator<Item = (usize, usize, &mut T)> {
| - let's call the lifetime of this reference `'1`
64 | self.items.iter_mut().enumerate().map(move |(index, item)| {
| --------------------- ^^^^^^^^^^^^^^^^^^^^ move out of `self` occurs here
| |
| _________borrow of `self.items` occurs here
| |
65 | | let (x, y) = self.index_to_coordinate(index);
| | ---- move occurs due to use in closure
66 | | (x, y, item)
67 | | })
| |__________- returning this value requires that `self.items` is borrowed for `'1`
For more information about this error, try `rustc --explain E0505`.
error: could not compile `grid` due to previous error
warning: build failed, waiting for other jobs to finish...
I know that I could write the method index_to_coordinate() as a pure function, but I would like a solution, that uses the member function similarly to enumerate().
Can this be done? If so, how?
I would like a solution, that uses the member function similarly to enumerate(). Can this be done? If so, how?
It cannot be done. You cannot borrow self while self.items is mutably borrowed. Full stop. Consider this formulation that does work without a member function:
pub fn enumerate_mut(&mut self) -> impl Iterator<Item = (usize, usize, &mut T)> {
self.items.iter_mut().enumerate().map(|(index, item)| {
let x = index % self.width;
let y = (index - x) / self.width;
(x, y, item)
})
}
The only way this works is because of disjoint borrows, i.e. the compiler knows that .width and .height are completely separate objects from .items (and actually this only works in 2021 edition since the disjoint borrows happen both inside and outside the closure). If you use a member of self though, the compiler has lost that knowledge and has to consider that self can access items within that member function, which wouldn't be allowed since the mutable borrow earlier must stay exclusive. Using the member function in the enumerate() method works since immutable borrows can be shared.
Function signatures are the contracts that borrow-checking, type-checking, and type-inference build off of. If the member function has access to self, it must be assumed that it will access all of self. There is no syntax for partial-borrows across a function interface.
It cannot be done at all? Even if I used unsafe?
Even with unsafe, you are not allowed to violate Rust's borrowing rules, so you can't have a &Self while its .items is mutably borrowed. You can access the .width and .height but it must be done via a pointer: *const Self. Here's what that'd look like (tested with Miri on the playground):
pub fn enumerate_mut(&mut self) -> impl Iterator<Item = (usize, usize, &mut T)> {
let this = self as *const Self;
self.items.iter_mut().enumerate().map(move |(index, item)| {
let (x, y) = unsafe { Self::index_to_coordinate(this, index) };
(x, y, item)
})
}
unsafe fn index_to_coordinate(this: *const Self, index: usize) -> (usize, usize) {
let width = *std::ptr::addr_of!((*this).width);
let height = *std::ptr::addr_of!((*this).height);
let x = index % width;
let y = (index - x) / width;
(x, y)
}
However, I hope we can agree that this wouldn't be a member function anymore since it is lacking the self.index_to_coordinate syntax. Of course I'm not advocating you use this at all, it's just a demonstration that even going to the absurd it is not possible.
Just use a free function. :)

Return only an owned type from a trait method that can accept an owned or borrowed value as input

I want to have a trait that can be implemented for T and &T but has methods that always return T.
What I would like to do is something like this
use std::borrow::ToOwned;
trait Foo<X: ToOwned> {
fn f(&self, x: X) -> f64;
fn g(&self) -> X::Owned;
}
struct Float(f64);
impl Foo<f64> for Float {
fn f(&self, x: f64) -> f64 {
x + self.0
}
fn g(&self) -> f64 {
self.0 * 2.0
}
}
struct List(Vec<f64>);
impl Foo<&Vec<f64>> for List {
fn f(&self, x: &Vec<f64>) -> f64 {
x.iter().sum()
}
// Error here - `&Vec<f64>` return type expected
fn g(&self) -> Vec<f64> {
self.0.iter().map(|&x| 2.0 * x).collect()
}
}
fn main() {
let float = Float(2.0);
println!("{} {}", float.f(3.0), float.g());
let list = List(vec![0.0, 1.0, 2.0]);
println!("{} {:?}", list.f(&vec![1.0, 2.0]), list.g());
}
I know that one option is to have a trait that defines the output type like so
trait FooReturn {
type Output;
}
trait Foo<X: FooReturn> {
fn f(&self, x: X) -> f64;
fn g(&self) -> X::Output;
}
then implement the trait for all relevant types, but I was wondering if there was a more standard/robust way to do this.
This is how you would do it once specialization is complete. Meanwhile, I couldn't even get a simple working example to compile on 1.55.0-nightly.
#![feature(specialization)]
trait MaybeOwned {
type Owned;
}
default impl<X> MaybeOwned for X {
type Owned = X;
}
impl<'a, X> MaybeOwned for &'a X {
type Owned = X;
}
trait Foo<X: MaybeOwned> {
fn f(&self, x: &X) -> f64;
fn g(&self) -> <X as MaybeOwned>::Owned;
}

Struggling with interior mutability

I have a data structure like this:
struct R {
hmhs: HashMap<i64, HashSet<i64>>,
}
impl R {
fn hs_for_hmhs(&mut self) -> &mut HashSet<i64> {
if let None = self.hmhs.get(&0) {
self.hmhs.insert(0, HashSet::new());
}
self.hmhs.get_mut(&0).unwrap()
}
fn iter_for_hmhs<'a>(&'a mut self) -> impl Iterator<Item = &'a i64> {
self.hs_for_hmhs().iter()
}
fn insert_for_hmhs(&mut self, i: i64) -> bool {
self.hs_for_hmhs().insert(i)
}
}
This seems to work, but all the methods require a mutable
reference to self which is unfortunate. I tried to give
interior mutability a go:
struct S {
hmhs: RefCell<HashMap<i64, HashSet<i64>>>,
}
impl S {
fn hs_for_hmhs(&self) -> &HashSet<i64> {
if let None = self.hmhs.borrow().get(&0) {
self.hmhs.borrow_mut().insert(0, HashSet::new());
}
self.hmhs.borrow_mut().get_mut(&0).unwrap()
}
fn iter_for_hmhs(&mut self) -> impl Iterator<Item = &i64> {
self.hs_for_hmhs().iter()
}
fn insert_for_hmhs(&mut self, i: i64) -> bool {
self.hs_for_hmhs().insert(i)
}
}
However, I constantly seem to hit problems. Mostly some variety of How do I return a reference to something inside a RefCell without breaking encapsulation?
I have tried lots of variants here, but I am missing something
fundamental in my understanding. Is there a way of achieving what I
want?
Complete Code:
use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
struct R {
hmhs: HashMap<i64, HashSet<i64>>,
}
impl R {
fn hs_for_hmhs(&mut self) -> &mut HashSet<i64> {
if let None = self.hmhs.get(&0) {
self.hmhs.insert(0, HashSet::new());
}
self.hmhs.get_mut(&0).unwrap()
}
fn iter_for_hmhs<'a>(&'a mut self) -> impl Iterator<Item = &'a i64> {
self.hs_for_hmhs().iter()
}
fn insert_for_hmhs(&mut self, i: i64) -> bool {
self.hs_for_hmhs().insert(i)
}
}
struct S {
hmhs: RefCell<HashMap<i64, HashSet<i64>>>,
}
impl S {
fn hs_for_hmhs(&self) -> &mut HashSet<i64> {
if let None = self.hmhs.borrow().get(&0) {
self.hmhs.borrow_mut().insert(0, HashSet::new());
}
self.hmhs.borrow_mut().get_mut(&0).unwrap()
}
fn iter_for_hmhs(&self) -> impl Iterator<Item = &i64> {
self.hs_for_hmhs().iter()
}
fn insert_for_hmhs(&self, i: i64) -> bool {
self.hs_for_hmhs().insert(i)
}
}
fn main() {}
Compiler Message:
error[E0597]: borrowed value does not live long enough
--> src/main.rs:36:9
|
36 | self.hmhs.borrow_mut().get_mut(&0).unwrap()
| ^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
37 | }
| - temporary value only lives until here
|
note: borrowed value must be valid for the anonymous lifetime #1 defined on the method body at 31:5...
--> src/main.rs:31:5
|
31 | / fn hs_for_hmhs(&self) -> &mut HashSet<i64> {
32 | | if let None = self.hmhs.borrow().get(&0) {
33 | | self.hmhs.borrow_mut().insert(0, HashSet::new());
34 | | }
35 | |
36 | | self.hmhs.borrow_mut().get_mut(&0).unwrap()
37 | | }
| |_____^
I found a solution -- extract the HashMap as a raw pointer. This in turn means that I can get to the HashSet without shenanigans including returning a iterator.
I'm happy enough with this as a solution. The unsafe code is small and contained and if I understand the reason why the compiler is complaining without unsafe, it cannot occur in this code, since neither the HashMap nor the HashSet are ever removed or replaced after construction.
That was a lot of effort.
use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
struct R {
hmhs: HashMap<i64, HashSet<i64>>,
}
impl R {
fn hs_for_hmhs(&mut self) -> &mut HashSet<i64> {
if let None = self.hmhs.get(&0) {
self.hmhs.insert(0, HashSet::new());
}
self.hmhs.get_mut(&0).unwrap()
}
fn iter_for_hmhs<'a>(&'a mut self) -> impl Iterator<Item = &'a i64> {
self.hs_for_hmhs().iter()
}
fn insert_for_hmhs(&mut self, i: i64) -> bool {
self.hs_for_hmhs().insert(i)
}
}
struct S {
hmhs: RefCell<HashMap<i64, HashSet<i64>>>,
}
impl S {
fn hs_as_ptr(&self) -> *mut HashMap<i64, HashSet<i64>> {
self.hmhs.borrow_mut().entry(0).or_insert(HashSet::new());
self.hmhs.as_ptr()
}
fn mut_hs_for_hmhs(&mut self) -> &mut HashSet<i64> {
unsafe { (*self.hs_as_ptr()).get_mut(&0).unwrap() }
}
fn hs_for_hmhs(&self) -> &HashSet<i64> {
unsafe { (*self.hs_as_ptr()).get(&0).unwrap() }
}
fn iter_for_hmhs<'a>(&'a self) -> impl Iterator<Item = &'a i64> + 'a {
self.hs_for_hmhs().iter()
}
fn insert_for_hmhs(&mut self, i: i64) -> bool {
self.mut_hs_for_hmhs().insert(i)
}
}
fn main() {
let mut r = R {
hmhs: HashMap::new(),
};
let mut s = S {
hmhs: RefCell::new(HashMap::new()),
};
r.insert_for_hmhs(10);
s.insert_for_hmhs(20);
println!("r next: {:?}", r.iter_for_hmhs().next());
println!("s next: {:?}", s.iter_for_hmhs().next());
}
https://play.rust-lang.org/?gist=3ed1977bdd5f9f82d144fe128f618979&version=stable&mode=debug&edition=2015

Extend Iterator with a "mean" method

I'm trying to implement a mean method for Iterator, like it is done with sum.
However, sum is Iterator method, so I decided to implement trait for any type that implements Iterator:
pub trait Mean<A = Self>: Sized {
fn mean<I: Iterator<Item = A>>(iter: I) -> f64;
}
impl Mean for u64 {
fn mean<I: Iterator<Item = u64>>(iter: I) -> f64 {
//use zip to start enumeration from 1, not 0
iter.zip((1..))
.fold(0., |s, (e, i)| (e as f64 + s * (i - 1) as f64) / i as f64)
}
}
impl<'a> Mean<&'a u64> for u64 {
fn mean<I: Iterator<Item = &'a u64>>(iter: I) -> f64 {
iter.zip((1..))
.fold(0., |s, (&e, i)| (e as f64 + s * (i - 1) as f64) / i as f64)
}
}
trait MeanIterator: Iterator {
fn mean(self) -> f64;
}
impl<T: Iterator> MeanIterator for T {
fn mean(self) -> f64 {
Mean::mean(self)
}
}
fn main() {
assert_eq!([1, 2, 3, 4, 5].iter().mean(), 3.);
}
Playground
The error:
error[E0282]: type annotations needed
--> src/main.rs:26:9
|
26 | Mean::mean(self)
| ^^^^^^^^^^ cannot infer type for `Self`
Is there any way to fix the code, or it is impossible in Rust?
like it is done with sum
Let's review how sum works:
pub fn sum<S>(self) -> S
where
S: Sum<Self::Item>,
sum is implemented on any iterator, so long as the result type S implements Sum for the iterated value. The caller gets to pick the result type. Sum is defined as:
pub trait Sum<A = Self> {
pub fn sum<I>(iter: I) -> Self
where
I: Iterator<Item = A>;
}
Sum::sum takes an iterator of A and produces a value of the type it is implemented from.
We can copy-paste the structure, changing Sum for Mean and put the straightforward implementations:
trait MeanExt: Iterator {
fn mean<M>(self) -> M
where
M: Mean<Self::Item>,
Self: Sized,
{
M::mean(self)
}
}
impl<I: Iterator> MeanExt for I {}
trait Mean<A = Self> {
fn mean<I>(iter: I) -> Self
where
I: Iterator<Item = A>;
}
impl Mean for f64 {
fn mean<I>(iter: I) -> Self
where
I: Iterator<Item = f64>,
{
let mut sum = 0.0;
let mut count: usize = 0;
for v in iter {
sum += v;
count += 1;
}
if count > 0 {
sum / (count as f64)
} else {
0.0
}
}
}
impl<'a> Mean<&'a f64> for f64 {
fn mean<I>(iter: I) -> Self
where
I: Iterator<Item = &'a f64>,
{
iter.copied().mean()
}
}
fn main() {
let mean: f64 = [1.0, 2.0, 3.0].iter().mean();
println!("{:?}", mean);
let mean: f64 = std::array::IntoIter::new([-1.0, 2.0, 1.0]).mean();
println!("{:?}", mean);
}
You can do it like this, for example:
pub trait Mean {
fn mean(self) -> f64;
}
impl<F, T> Mean for T
where T: Iterator<Item = F>,
F: std::borrow::Borrow<f64>
{
fn mean(self) -> f64 {
self.zip((1..))
.fold(0.,
|s, (e, i)| (*e.borrow() + s * (i - 1) as f64) / i as f64)
}
}
fn main() {
assert_eq!([1f64, 2f64, 3f64, 4f64, 5f64].iter().mean(), 3.);
assert_eq!(vec![1f64, 2f64, 3f64, 4f64, 5f64].iter().mean(), 3.);
assert_eq!(vec![1f64, 2f64, 3f64, 4f64, 5f64].into_iter().mean(), 3.);
}
I used Borrow trait to support iterators over f64 and &f64.

Cannot modify a struct field from implementation: "cannot borrow immutable borrowed content as mutable"

I'm trying to implement an iterator which will yield prime numbers. I store already found prime numbers in a Vec<u64>.
Here's my implementation:
struct Primes {
primes: Vec<u64>,
}
impl Primes {
fn new() -> Primes {
Primes { primes: vec!(2, 3) }
}
fn iter(&self) -> PrimesIterator {
PrimesIterator { primes: &self.primes, index : 0 }
}
}
struct PrimesIterator<'a> {
primes: & 'a Vec<u64>,
index: usize,
}
impl<'a> Iterator for PrimesIterator<'a> {
type Item = u64;
fn next(&mut self) -> Option<u64> {
if self.index < self.primes.len() {
let result = self.primes[self.index];
self.index += 1;
Some(result)
} else {
let mut n = *self.primes.last().unwrap();
loop {
n += 2;
if is_prime(self.primes, n) {
self.primes.push(n);
self.index += 1;
return Some(n);
}
}
}
}
}
fn is_prime(primes: &[u64], n: u64) -> bool {
for &p in primes.iter() {
if n % p == 0 {
return false;
}
if p * p > n {
return true;
}
}
return false;
}
but when I'm trying to compile it, I'm getting the following error:
main.rs: error: cannot borrow immutable borrowed content `*self.primes` as mutable
main.rs: self.primes.push(n);
I declared self as &mut so I don't really understand what's wrong here and how to fix that.
Your PrimesIterator type contains a non-mutable reference to a Vec<u64>. You need to declare it as a mutable reference:
struct PrimesIterator<'a> {
primes: &'a mut Vec<u64>,
index: usize,
}
This will of course require you to also modify the iter() function to make sure it passes a mutable reference:
impl Primes {
fn new() -> Primes {
Primes { primes: vec!(2, 3) }
}
fn iter(&mut self) -> PrimesIterator {
PrimesIterator { primes: &mut self.primes, index : 0 }
}
}

Resources