Re: nogc Array

2016-01-25 Thread Igor via Digitalmars-d-learn

On Tuesday, 26 January 2016 at 03:06:40 UTC, maik klein wrote:

On Tuesday, 26 January 2016 at 03:03:40 UTC, Igor wrote:
Is there a GC-less array that we can use out of the box or do 
I have to create my own?


https://dlang.org/phobos/std_container_array.html


How do we use std.algorithm with it? I could like to use find but 
I have no luck.


I have

std.container.array!MyClass classes;

then std.algorithm.find!("a.myInt == b")(classes, 3)

I was hoping this would find the first object in classes who has 
myInt == 3 but I just get many errors about not being able to 
find the right definition.


I guess std.container.array isn't a range? Or am I using it wrong?



Re: how to allocate class without gc?

2016-01-25 Thread Mike Parker via Digitalmars-d-learn

On Tuesday, 26 January 2016 at 01:09:50 UTC, Igor wrote:
Is there any examples that shows how to properly allocate an 
object of a class type with the new allocators and then release 
it when desired?


Allocate a block of memory big enough to hold an instance of your 
class using whichever allocator you need, then instantiate a 
class instance with std.conv.emplace.


http://p0nce.github.io/d-idioms/#Placement-new-with-emplace


Re: how to allocate class without gc?

2016-01-25 Thread Ali Çehreli via Digitalmars-d-learn

On 01/25/2016 09:47 PM, Igor wrote:

> it fails because the string representing the name inside App is null...
> Which doesn't happen when I use new.

There must be something else going on. Do you see it with a simpler type?

> Should it work as expected(which it isn't)

new allocates and constructs, emplace does not allocate and construct. 
That shold be the only difference.


> or do I have to also emplace all the fields and such so they are not for
> some reason released?

Not at all.

Ali



Re: How can i track the GC when it's runing?

2016-01-25 Thread cym13 via Digitalmars-d-learn

On Monday, 25 January 2016 at 09:33:15 UTC, Dsby wrote:

I want to know How can i track the GC when it's runing?
And Which algorithm is  D's GC used,only Scan-Mark?


Something that isn't on Garry's link: if using dmd you can pass 
the "-profile=gc" flag which will do the GC configuration so that 
you get a summary of all allocations at the end of the program.


Re: nogc Array

2016-01-25 Thread Igor via Digitalmars-d-learn

On Tuesday, 26 January 2016 at 04:38:13 UTC, Adam D. Ruppe wrote:

On Tuesday, 26 January 2016 at 04:31:07 UTC, Igor wrote:

then std.algorithm.find!("a.myInt == b")(classes, 3)


Try

std.algorithm.find!("a.myInt == b")(classes[], 3)

notice the [] after classes


I guess std.container.array isn't a range? Or am I using it 
wrong?


Containers aren't really ranges, they instead *offer* ranges 
that iterate over them. Built in arrays are a bit special in 
that they do this implicitly so the line is more blurred there, 
but it is a general rule that you need to get a range out of a 
container.


Otherwise, consider that iterating over it with popFront would 
result in the container being automatically emptied and not 
reusable!


Ok, does the [] do any conversion or any thing I don't want or 
does it just make the template know we are working over an array?


Are there any performance issues? I am already using a for loop 
to find the type, it's 6 lines of code. I was hoping to get that 
down to one or 2 and make it a bit easier to understand.


App app = null;
for(int i = 0; i < Apps.length(); i++)
if ((Apps[i] !is null) && (Apps[i].hWnd == hWnd))
{
app = Apps[i];
break;
}

versus

find!("a.hWnd == b")(Apps[], hWnd);

Does [] take time to convert to a built in a array or range or 
whatever or will it be just as fast as the above code?





Re: Improving CSV parsing performance, Episode 2 (Was: Re: Speed of csvReader)

2016-01-25 Thread H. S. Teoh via Digitalmars-d-learn
On Sun, Jan 24, 2016 at 06:07:41AM +, Jesse Phillips via 
Digitalmars-d-learn wrote:
[...]
> My suggestion is to take the unittests used in std.csv and try to get
> your code working with them. As fastcsv limitations would prevent
> replacing the std.csv implementation the API may not need to match,
> but keeping close to the same would be best.

My thought is to integrate the fastcsv code into std.csv, such that the
current std.csv code will serve as fallback in the cases where fastcsv's
limitations would prevent it from being used, with fastcsv being chosen
where possible.

It may be possible to lift some of fastcsv's limitations, now that a few
performance bottlenecks have been identified (validation, excessive
number of small allocations, being the main ones). The code could be
generalized a bit more while preserving the optimizations in these key
areas.


T

-- 
BREAKFAST.COM halted...Cereal Port Not Responding. -- YHL


Re: nogc Array

2016-01-25 Thread Kapps via Digitalmars-d-learn

On Tuesday, 26 January 2016 at 04:31:07 UTC, Igor wrote:

On Tuesday, 26 January 2016 at 03:06:40 UTC, maik klein wrote:

On Tuesday, 26 January 2016 at 03:03:40 UTC, Igor wrote:
Is there a GC-less array that we can use out of the box or do 
I have to create my own?


https://dlang.org/phobos/std_container_array.html


How do we use std.algorithm with it? I could like to use find 
but I have no luck.


I have

std.container.array!MyClass classes;

then std.algorithm.find!("a.myInt == b")(classes, 3)

I was hoping this would find the first object in classes who 
has myInt == 3 but I just get many errors about not being able 
to find the right definition.


I guess std.container.array isn't a range? Or am I using it 
wrong?


First, should be std.container.array.Array!MyClass. However I 
don't think(?) that the Array struct is a range itself, you might 
have to use classes[] instead to get a slice of the array.


Re: nogc Array

2016-01-25 Thread Jonathan M Davis via Digitalmars-d-learn
On Tuesday, January 26, 2016 03:03:40 Igor via Digitalmars-d-learn wrote:
> Is there a GC-less array that we can use out of the box or do I
> have to create my own?

If what you want is a dynamic array (as opposed std.container.Array), then
you can simply malloc the memory and then slice it to get a dynamic array.
It's just that it's then up to you to manage the memory properly, and if you
attempt to append or concatenate, it'll result in the GC allocating a new
array.

- Jonathan M Davis



Re: nogc Array

2016-01-25 Thread Adam D. Ruppe via Digitalmars-d-learn

On Tuesday, 26 January 2016 at 04:31:07 UTC, Igor wrote:

then std.algorithm.find!("a.myInt == b")(classes, 3)


Try

std.algorithm.find!("a.myInt == b")(classes[], 3)

notice the [] after classes


I guess std.container.array isn't a range? Or am I using it 
wrong?


Containers aren't really ranges, they instead *offer* ranges that 
iterate over them. Built in arrays are a bit special in that they 
do this implicitly so the line is more blurred there, but it is a 
general rule that you need to get a range out of a container.


Otherwise, consider that iterating over it with popFront would 
result in the container being automatically emptied and not 
reusable!


Re: how to allocate class without gc?

2016-01-25 Thread Igor via Digitalmars-d-learn

On Tuesday, 26 January 2016 at 05:11:54 UTC, Mike Parker wrote:

On Tuesday, 26 January 2016 at 01:09:50 UTC, Igor wrote:
Is there any examples that shows how to properly allocate an 
object of a class type with the new allocators and then 
release it when desired?


Allocate a block of memory big enough to hold an instance of 
your class using whichever allocator you need, then instantiate 
a class instance with std.conv.emplace.


http://p0nce.github.io/d-idioms/#Placement-new-with-emplace


I created a class using this example. But my code is now failing. 
It seems one can't just replace new with this and expect it to 
work?


What is happening is some fields(strings) are not retaining their 
value.


ubyte[__traits(classInstanceSize, App)] buffer;
auto app = cast(App)emplace!App(buffer[]);
//auto app = new App();

Basically the comment is the original. When I finally call 
createWindow, it fails because the string representing the name 
inside App is null... Which doesn't happen when I use new.


Should it work as expected(which it isn't) or do I have to also 
emplace all the fields and such so they are not for some reason 
released?




Re: New Win32 Core api broke?

2016-01-25 Thread Mike Parker via Digitalmars-d-learn

On Monday, 25 January 2016 at 22:57:22 UTC, Igor wrote:
 error LNK2019: unresolved external symbol GetStockObject 
referenced in function _D2Application10createWindowMFPFZvZi 
(int Application.createWindow(void function()*))


and the line of code is

wc.hbrBackground = GetStockObject(WHITE_BRUSH);

I've tried to

import core.sys.windows.wingdi;

But that just got me to this error. When I don't use it, the 
code compiles


I was able to solve this problem by importing gdi32.lib on the 
command line.  Shouldn't the module import the lib like it does 
for the other ones? or does it?


For clarity, libraries are not imported, they are linked. 
*Modules* are imported. Imports are processed at compile time to 
determine which symbols are available for use in the current 
compilation units. Libraries and object files are processed by 
the linker after compilation and imports have no role to play in 
that. Unresolved external symbol errors are linker errors, 
meaning you used a symbol in your code, the linker looked for its 
copied form in all the available object files (including any 
libraries it was given) and couldn't find it.


The Windows API is implemented in multiple libraries. I believe 
DMD links to kernel32.lib and user32.lib by default, as those 
contain the most commonly used functions, but if you want to call 
any functions from any of the other Win32 libraries, you will 
need to link with them manually either by passing them on the 
command line or by using a lib pragma. If you aren't sure which 
library needs linking with when you get a missing symbol, the 
thing to do is to look up the function in the MSDN (Microsoft 
Developer Network) documentation and it will tell you which 
library you need. Usually it's enough to feed the function to 
Google and you will get the MSDN page in one of the first few 
links (though you'll need to make sure to go to the Win32 API 
page and not the documentation for the .NET version of the 
function).





Re: New Win32 Core api broke?

2016-01-25 Thread Mike Parker via Digitalmars-d-learn

On Tuesday, 26 January 2016 at 05:05:43 UTC, Mike Parker wrote:


the linker looked for its copied form


*compiled* form


Re: is there a set container?

2016-01-25 Thread Adam D. Ruppe via Digitalmars-d-learn

The std.container.RedBlackTree is close:

http://dlang.org/phobos/std_container_rbtree.html


Or you may prefer my work-in-progress unofficial docs:

http://dpldocs.info/experimental-docs/std.container.rbtree.RedBlackTree.html

You can see methods there like insert, removeKey, and 
opBinaryRight, which is actually the in operator:


http://dpldocs.info/experimental-docs/std.container.rbtree.RedBlackTree.opBinaryRight.html

to see if an element exists in the set.


Create a red black tree with this convenience function:

http://dpldocs.info/experimental-docs/std.container.rbtree.redBlackTree.1.html


is there a set container?

2016-01-25 Thread Namal via Digitalmars-d-learn

Hello,

I am looking for data structure equivalent to std::set from C++. 
Couldn't find it in the documentation.


Error using templates: "cannot use template to add field to aggregate ''"

2016-01-25 Thread pineapple via Digitalmars-d-learn
I'm getting several of these since I'm trying to do the same 
thing in a few places. Here's a complete error:


path\to\file.d(55): Error: variable 
units.unitvalue.opmethod!("sum(in unitvalue value)", 
"add(value)").methodtemplate cannot use template to add field to 
aggregate 'unitvalue'
path\to\file.d(127): Error: template instance 
units.unitvalue.opmethod!("sum(in unitvalue value)", 
"add(value)") error instantiating


In this class I wrote a number of methods like "multiply", 
"divide", "add", "subtract" and I want to add alternatives that 
don't modify the object. In this particular instance, I'm trying 
to wrap the "add" method in another named "sum" that doesn't 
modify the original object, simply by making a copy first and 
operating upon that instead.


What am I doing wrong?

The relevant bits of my class look like this:

class unitvalue{
double coefficient;
int[unit] exponents;

unitvalue copy(){
unitvalue value = new unitvalue();
value.coefficient = this.coefficient;
value.exponents = this.exponents.dup;
return value;
}

template opmethod(string methoddef, string methodcall){
const char[] methodtemplate =
"unitvalue " ~ methoddef ~ "{
unitvalue copy = this.copy();
copy." ~ methodcall ~ ";
return copy;
}"
;
}

mixin(unitvalue.opmethod!(
"sum(in unitvalue value)", "add(value)"
));
void add(in unitvalue value){
if(!this.samedimensions(value)){
throw new Exception("Cannot add values of differing 
dimensions.");

}else{
this.coefficient += value.coefficient;
}
}

bool samedimensions(in unitvalue value){
return this.exponents == value.exponents;
}
}



Re: Collapsing n-dimensional array to linear (1 dimensional)

2016-01-25 Thread ixid via Digitalmars-d-learn

On Monday, 25 January 2016 at 08:31:14 UTC, abad wrote:

On Monday, 25 January 2016 at 02:27:57 UTC, Solomon E wrote:

On Saturday, 23 January 2016 at 07:57:55 UTC, Ali Çehreli
Ruby's Array class includes this sort method for flattening and 
for me it was surprisingly useful, for instance when it was 
necessary to write the array to file.


D could certainly add a few more helper functions to work on 
multidimensional data or perhaps an article, I admit I was 
unaware joiner could be chained without mapping like that. One 
that regularly irritates me is arrays of results that you want to 
make eager such that you can map a lazy function to a 2D array 
and then store the result in a 2D array again. This seems messy 
and I'd like a function that will take absolutely anything and 
force eager assessment.


auto a = res.map!array.array; // De-lazying 2D result

Would like:

auto a = res.eager;


D Dll's usefulness

2016-01-25 Thread Igor via Digitalmars-d-learn
Can D Dll's be linked and used as if they were compiled directly 
with the program? I was thinking of writing some library routines 
and put them in a Dll but now I'm not thinking that would be very 
useful because the Dll's won't export class like behavior.


in my DLL:

class MyClass { void foo() { } }

in my app:

auto c = new MyClass();

I'd like to use MyClass as if it were defined directly here, but 
I think I can only load the dll and attach to foo? Is this right?


Since I'm the "owner" of the library I can always just "drag and 
drop" the source code into the project to get the desired 
behavior. I'd like the DLL to provide that to future projects 
that may not have the source code. Either the DLL's don't support 
this, which I think is the case, or I have to include a "header".


Hopefully there is a tool that could take a "library" that will 
be used as a dll and strip it down into modules that can be 
included into the main app so it can be used as if the source 
code was directly compiled in.


Am I off target here?










Re: Error using templates: "cannot use template to add field to aggregate ''"

2016-01-25 Thread pineapple via Digitalmars-d-learn
Thanks so much for the help! I'm still getting used to D's 
compile-time code.


Re: Error using templates: "cannot use template to add field to aggregate ''"

2016-01-25 Thread anonymous via Digitalmars-d-learn

On 25.01.2016 15:51, pineapple wrote:

class unitvalue{
 double coefficient;
 int[unit] exponents;

 unitvalue copy(){
 unitvalue value = new unitvalue();
 value.coefficient = this.coefficient;
 value.exponents = this.exponents.dup;
 return value;
 }

 template opmethod(string methoddef, string methodcall){
 const char[] methodtemplate =


Can't have variables like that in templates. Make it a "manifest 
constant" with  enum. Also, if you want opmethod!("foo", "bar") to 
evaluate to the code, then methodtemplate needs to be renamed to 
"opmethod". I.e., make this line:


enum opmethod =


Also, opmethod doesn't need to be template. A function would work as well:

static string opmethod(string methoddef, string methodcall)
{
return
"unitvalue " ~ methoddef ~ "{
unitvalue copy = this.copy();
copy." ~ methodcall ~ ";
return copy;
}"
;
}

mixin(unitvalue.opmethod(
"sum(in unitvalue value)", "add(value)"
));



 "unitvalue " ~ methoddef ~ "{
 unitvalue copy = this.copy();
 copy." ~ methodcall ~ ";
 return copy;
 }"
 ;
 }

 mixin(unitvalue.opmethod!(
 "sum(in unitvalue value)", "add(value)"
 ));
 void add(in unitvalue value){
 if(!this.samedimensions(value)){
 throw new Exception("Cannot add values of differing
dimensions.");
 }else{
 this.coefficient += value.coefficient;
 }
 }

 bool samedimensions(in unitvalue value){
 return this.exponents == value.exponents;


This gives me an error, too: "Error: incompatible types for 
((this.exponents) == (value.exponents)): 'int[int]' and 'const(int[int])'"


(I've aliased unit to int.)

As far as I can tell, this should work. There's a bugzilla issue for it:
https://issues.dlang.org/show_bug.cgi?id=13622

You can work around the bogus error message by using a const temporary 
for this.exponent:


const this_exponents = this.exponents;
return this_exponents == value.exponents;



 }
}





Re: Error using templates: "cannot use template to add field to aggregate ''"

2016-01-25 Thread Chris Wright via Digitalmars-d-learn
On Mon, 25 Jan 2016 14:51:21 +, pineapple wrote:

> I'm getting several of these since I'm trying to do the same thing in a
> few places. Here's a complete error:
> 
>  path\to\file.d(55): Error: variable
> units.unitvalue.opmethod!("sum(in unitvalue value)",
> "add(value)").methodtemplate cannot use template to add field to
> aggregate 'unitvalue'
>  path\to\file.d(127): Error: template instance
> units.unitvalue.opmethod!("sum(in unitvalue value)", "add(value)") error
> instantiating

That looks like the right error.

>  template opmethod(string methoddef, string methodcall){
>  const char[] methodtemplate =

Change it from 'const' to 'enum' and Bob's your uncle.

Short explanation:

'enum' refers to compile-time constants. 'const' is a promise that you 
will not mutate a variable through that reference. Anything that's not a 
compile-time constant in an aggregate body requires storage space within 
that aggregate, resulting in an unbounded set of fields.

Exhaustive explanation:

'const' indicates that you cannot mutate the data through this reference 
(but it can be mutated elsewhere). It's not referring to compile-time 
constants. For instance, it's entirely legal (and reasonable) to write:

class OptParse {
  const(string[]) args;
  this(const(string[]) args) {
this.args = args;
  }
}
void main(string[] args) {
  new OptParse(args);
}

Which indicates that OptParse is not going to modify the args array. 
You're grabbing command-line arguments and passing them in, which means 
they're not a compile-time constant. So the OptParse class has to include 
a storage slot reserved for the 'args' variable.

In your case, 'methodtemplate' isn't declared as a compile-time constant. 
It has an initializer that's a compile-time constant, but you aren't 
guaranteeing that the value isn't going to be changed.

That would be fine, but it's inside a template. Templates can be 
instantiated a potentially unlimited number of times. So the compiler 
comes across this type, tries to compute its size and fields -- but it 
doesn't know for certain at this point how many times you're 
instantiating the template. So it can't list out all the fields.

It would be possible if D compiled a whole program at once. This would 
prevent you from publishing closed-source libraries, however, and 
increase compilation times.


Re: First project: questions on how-to, and on language features

2016-01-25 Thread Ali Çehreli via Digitalmars-d-learn

On 01/24/2016 04:26 AM, Marc Schütz wrote:

>> (2) In the unittest code, I have a block that I want to rewrite using
>> assertThrown, but I can't figure out from either the book or the
>> website the correct usage.  What's the right way to specify a
>> StringException with a particular message I expect to receive?
>
> Here's the relevant documentation:
> https://dlang.org/phobos/std_exception.html#.assertThrown
> https://dlang.org/phobos/std_exception.html#.collectExceptionMsg

Here is another link for completeness:


http://ddili.org/ders/d.en/unit_testing.html#ix_unit_testing.assertThrown,%20std.exception

Ali



Re: D Dll's usefulness

2016-01-25 Thread Kagamin via Digitalmars-d-learn
Um... A closed-source library is one thing, DLL is another thing, 
DLL class library is a third thing, seamless linking of DLL class 
library is a fourth thing. Well... see what you can get working.


Re: D Dll's usefulness

2016-01-25 Thread Igor via Digitalmars-d-learn

On Monday, 25 January 2016 at 21:42:07 UTC, Kagamin wrote:
Um... A closed-source library is one thing, DLL is another 
thing, DLL class library is a third thing, seamless linking of 
DLL class library is a fourth thing. Well... see what you can 
get working.


Thanks for the help! I really appreciate your wisdom and 
hospitality! Give me your address and I'll send you a thank you 
card!


New Win32 Core api broke?

2016-01-25 Thread Igor via Digitalmars-d-learn
 error LNK2019: unresolved external symbol GetStockObject 
referenced in function _D2Application10createWindowMFPFZvZi (int 
Application.createWindow(void function()*))


and the line of code is

wc.hbrBackground = GetStockObject(WHITE_BRUSH);

I've tried to

import core.sys.windows.wingdi;

But that just got me to this error. When I don't use it, the code 
compiles


I was able to solve this problem by importing gdi32.lib on the 
command line.  Shouldn't the module import the lib like it does 
for the other ones? or does it?


static assignment

2016-01-25 Thread Igor via Digitalmars-d-learn

how can I have a static assignment


static bool isStarted = false;
	public static Application Start(string Name, void 
function(Application) entryPoint)

{
if (isStarted)
assert("Can only call Start once");
isStarted = true;
...

but I don't want this a runtime check. I want to know at compile 
time. Start should never be used more than once in the entire 
program. It's only used to get control from windows startup. It's 
only called in the static this() of the main module.


changing stuff to static if and static assert doesn't help. I 
tried enum, const, etc but all prevent setting isStarted to true.










Re: static assignment

2016-01-25 Thread Steven Schveighoffer via Digitalmars-d-learn

On 1/25/16 8:40 PM, Igor wrote:

how can I have a static assignment


 static bool isStarted = false;
 public static Application Start(string Name, void
function(Application) entryPoint)
 {
 if (isStarted)
 assert("Can only call Start once");
 isStarted = true;
 ...

but I don't want this a runtime check.


I'm not sure you even need to worry about this check at all. Just don't 
call the function again!


If you don't want other modules to have access, make the function 
private in its own module. Then nothing else can call it. Of course, you 
have to either name it properly or have the startup code in the same 
module (I'm unsure how Windows does this).


But I think if you want the check, it necessarily must be during 
runtime. At compile time, the code isn't running, it's just compiling.


-Steve


how to allocate class without gc?

2016-01-25 Thread Igor via Digitalmars-d-learn
Is there any examples that shows how to properly allocate an 
object of a class type with the new allocators and then release 
it when desired?




Re: Collapsing n-dimensional array to linear (1 dimensional)

2016-01-25 Thread abad via Digitalmars-d-learn

On Monday, 25 January 2016 at 02:27:57 UTC, Solomon E wrote:

On Saturday, 23 January 2016 at 07:57:55 UTC, Ali Çehreli wrote:


auto collapse(R)(R r)
if (isArray!R) {
return r.joiner.collapse.joiner;
}

auto collapse(R)(R r)
if (!isArray!R) {
return r;
}



Ali, that code only passed the one test it had for collapsing a 
three level array. It wouldn't collapse arrays of other numbers 
of levels. It wasn't recursing as appeared to be intended.


Is the following code better D? (I don't know because I'm still 
learning D, so I'd like to be corrected if the comments in my 
code are inaccurate or misleading.)


(See https://issues.dlang.org/show_bug.cgi?id=12062 for where I 
got the idea that `flatten` should be defined to mutate by 
reference. A comment there suggests to use 
std.experimental.ndslice and byElement for that, but ndlslice 
doesn't seem to be in the library anymore.)




I will give this a try later.

Ruby's Array class includes this sort method for flattening and 
for me it was surprisingly useful, for instance when it was 
necessary to write the array to file.


I will also take a look at ndslice and see how intuitive its 
approach for achieving this would be.




How can i track the GC when it's runing?

2016-01-25 Thread Dsby via Digitalmars-d-learn

I want to know How can i track the GC when it's runing?
And Which algorithm is  D's GC used,only Scan-Mark?



Re: How can i track the GC when it's runing?

2016-01-25 Thread Gary Willoughby via Digitalmars-d-learn

On Monday, 25 January 2016 at 09:33:15 UTC, Dsby wrote:

I want to know How can i track the GC when it's runing?
And Which algorithm is  D's GC used,only Scan-Mark?


There is a good resource here:

https://dlang.org/spec/garbage.html

It details compiler flags to use to profile and log the GC usage.


nogc Array

2016-01-25 Thread Igor via Digitalmars-d-learn
Is there a GC-less array that we can use out of the box or do I 
have to create my own?




Re: nogc Array

2016-01-25 Thread maik klein via Digitalmars-d-learn

On Tuesday, 26 January 2016 at 03:03:40 UTC, Igor wrote:
Is there a GC-less array that we can use out of the box or do I 
have to create my own?


https://dlang.org/phobos/std_container_array.html


Re: nogc Array

2016-01-25 Thread Nemo via Digitalmars-d-learn

On Tuesday, 26 January 2016 at 03:03:40 UTC, Igor wrote:
Is there a GC-less array that we can use out of the box or do I 
have to create my own?


There's one in emsi containers.