Revision: 16762
Author: [email protected]
Date: Tue Sep 17 11:34:20 2013 UTC
Log: Handlify JSReceiver::HasProperty and friends.
[email protected]
Review URL: https://codereview.chromium.org/23496058
http://code.google.com/p/v8/source/detail?r=16762
Modified:
/branches/bleeding_edge/src/api.cc
/branches/bleeding_edge/src/objects-inl.h
/branches/bleeding_edge/src/objects.cc
/branches/bleeding_edge/src/objects.h
/branches/bleeding_edge/src/runtime.cc
/branches/bleeding_edge/test/cctest/test-heap.cc
/branches/bleeding_edge/test/cctest/test-mark-compact.cc
=======================================
--- /branches/bleeding_edge/src/api.cc Mon Sep 16 14:09:22 2013 UTC
+++ /branches/bleeding_edge/src/api.cc Tue Sep 17 11:34:20 2013 UTC
@@ -2056,7 +2056,7 @@
i::HandleScope scope(isolate_);
i::Handle<i::JSObject> obj(i::JSObject::cast(raw_obj), isolate_);
i::Handle<i::String> name = isolate_->factory()->stack_string();
- if (!obj->HasProperty(*name)) return v8::Local<Value>();
+ if (!i::JSReceiver::HasProperty(obj, name)) return v8::Local<Value>();
i::Handle<i::Object> value = i::GetProperty(isolate_, obj, name);
if (value.is_null()) return v8::Local<Value>();
return v8::Utils::ToLocal(scope.CloseAndEscape(value));
@@ -3625,7 +3625,7 @@
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ON_BAILOUT(isolate, "v8::Object::HasProperty()", return false);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
- return self->HasElement(index);
+ return i::JSReceiver::HasElement(self, index);
}
@@ -3679,8 +3679,8 @@
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ON_BAILOUT(isolate, "v8::Object::HasOwnProperty()",
return false);
- return Utils::OpenHandle(this)->HasLocalProperty(
- *Utils::OpenHandle(*key));
+ return i::JSReceiver::HasLocalProperty(
+ Utils::OpenHandle(this), Utils::OpenHandle(*key));
}
=======================================
--- /branches/bleeding_edge/src/objects-inl.h Tue Sep 17 11:01:43 2013 UTC
+++ /branches/bleeding_edge/src/objects-inl.h Tue Sep 17 11:34:20 2013 UTC
@@ -5714,19 +5714,23 @@
}
-bool JSReceiver::HasProperty(Name* name) {
- if (IsJSProxy()) {
- return JSProxy::cast(this)->HasPropertyWithHandler(name);
+bool JSReceiver::HasProperty(Handle<JSReceiver> object,
+ Handle<Name> name) {
+ if (object->IsJSProxy()) {
+ Handle<JSProxy> proxy = Handle<JSProxy>::cast(object);
+ return JSProxy::HasPropertyWithHandler(proxy, name);
}
- return GetPropertyAttribute(name) != ABSENT;
+ return object->GetPropertyAttribute(*name) != ABSENT;
}
-bool JSReceiver::HasLocalProperty(Name* name) {
- if (IsJSProxy()) {
- return JSProxy::cast(this)->HasPropertyWithHandler(name);
+bool JSReceiver::HasLocalProperty(Handle<JSReceiver> object,
+ Handle<Name> name) {
+ if (object->IsJSProxy()) {
+ Handle<JSProxy> proxy = Handle<JSProxy>::cast(object);
+ return JSProxy::HasPropertyWithHandler(proxy, name);
}
- return GetLocalPropertyAttribute(name) != ABSENT;
+ return object->GetLocalPropertyAttribute(*name) != ABSENT;
}
@@ -5768,21 +5772,23 @@
}
-bool JSReceiver::HasElement(uint32_t index) {
- if (IsJSProxy()) {
- return JSProxy::cast(this)->HasElementWithHandler(index);
+bool JSReceiver::HasElement(Handle<JSReceiver> object, uint32_t index) {
+ if (object->IsJSProxy()) {
+ Handle<JSProxy> proxy = Handle<JSProxy>::cast(object);
+ return JSProxy::HasElementWithHandler(proxy, index);
}
- return JSObject::cast(this)->GetElementAttributeWithReceiver(
- this, index, true) != ABSENT;
+ return Handle<JSObject>::cast(object)->GetElementAttributeWithReceiver(
+ *object, index, true) != ABSENT;
}
-bool JSReceiver::HasLocalElement(uint32_t index) {
- if (IsJSProxy()) {
- return JSProxy::cast(this)->HasElementWithHandler(index);
+bool JSReceiver::HasLocalElement(Handle<JSReceiver> object, uint32_t
index) {
+ if (object->IsJSProxy()) {
+ Handle<JSProxy> proxy = Handle<JSProxy>::cast(object);
+ return JSProxy::HasElementWithHandler(proxy, index);
}
- return JSObject::cast(this)->GetElementAttributeWithReceiver(
- this, index, false) != ABSENT;
+ return Handle<JSObject>::cast(object)->GetElementAttributeWithReceiver(
+ *object, index, false) != ABSENT;
}
=======================================
--- /branches/bleeding_edge/src/objects.cc Tue Sep 17 11:01:43 2013 UTC
+++ /branches/bleeding_edge/src/objects.cc Tue Sep 17 11:34:20 2013 UTC
@@ -460,11 +460,10 @@
}
-bool JSProxy::HasElementWithHandler(uint32_t index) {
- String* name;
- MaybeObject* maybe = GetHeap()->Uint32ToString(index);
- if (!maybe->To<String>(&name)) return maybe;
- return HasPropertyWithHandler(name);
+bool JSProxy::HasElementWithHandler(Handle<JSProxy> proxy, uint32_t index)
{
+ Isolate* isolate = proxy->GetIsolate();
+ Handle<String> name = isolate->factory()->Uint32ToString(index);
+ return HasPropertyWithHandler(proxy, name);
}
@@ -3440,17 +3439,14 @@
}
-bool JSProxy::HasPropertyWithHandler(Name* name_raw) {
- Isolate* isolate = GetIsolate();
- HandleScope scope(isolate);
- Handle<Object> receiver(this, isolate);
- Handle<Object> name(name_raw, isolate);
+bool JSProxy::HasPropertyWithHandler(Handle<JSProxy> proxy, Handle<Name>
name) {
+ Isolate* isolate = proxy->GetIsolate();
// TODO(rossberg): adjust once there is a story for symbols vs proxies.
if (name->IsSymbol()) return false;
Handle<Object> args[] = { name };
- Handle<Object> result = CallTrap(
+ Handle<Object> result = proxy->CallTrap(
"has", isolate->derived_has_trap(), ARRAY_SIZE(args), args);
if (isolate->has_pending_exception()) return false;
@@ -5124,7 +5120,7 @@
Handle<Object> old_value;
bool should_enqueue_change_record = false;
if (FLAG_harmony_observation && object->map()->is_observed()) {
- should_enqueue_change_record = object->HasLocalElement(index);
+ should_enqueue_change_record = HasLocalElement(object, index);
if (should_enqueue_change_record) {
old_value = object->GetLocalElementAccessorPair(index) != NULL
? Handle<Object>::cast(factory->the_hole_value())
@@ -5140,7 +5136,7 @@
result = AccessorDelete(object, index, mode);
}
- if (should_enqueue_change_record && !object->HasLocalElement(index)) {
+ if (should_enqueue_change_record && !HasLocalElement(object, index)) {
Handle<String> name = factory->Uint32ToString(index);
EnqueueChangeRecord(object, "deleted", name, old_value);
}
@@ -5215,7 +5211,7 @@
result = DeleteNormalizedProperty(object, name, mode);
}
- if (is_observed && !object->HasLocalProperty(*name)) {
+ if (is_observed && !HasLocalProperty(object, name)) {
EnqueueChangeRecord(object, "deleted", name, old_value);
}
@@ -6166,7 +6162,7 @@
bool preexists = false;
if (is_observed) {
if (is_element) {
- preexists = object->HasLocalElement(index);
+ preexists = HasLocalElement(object, index);
if (preexists && object->GetLocalElementAccessorPair(index) == NULL)
{
old_value = Object::GetElement(isolate, object, index);
}
=======================================
--- /branches/bleeding_edge/src/objects.h Tue Sep 17 11:01:43 2013 UTC
+++ /branches/bleeding_edge/src/objects.h Tue Sep 17 11:34:20 2013 UTC
@@ -1950,7 +1950,7 @@
// Casting.
static inline JSReceiver* cast(Object* obj);
- // Implementation of [[Put]], see ECMA-262 5th edition, section 8.12.5.
+ // Implementation of [[Put]], ECMA-262 5th edition, section 8.12.5.
static Handle<Object> SetProperty(Handle<JSReceiver> object,
Handle<Name> key,
Handle<Object> value,
@@ -1967,7 +1967,13 @@
MUST_USE_RESULT MaybeObject* SetPropertyWithDefinedSetter(JSReceiver*
setter,
Object* value);
- // Implementation of [[Delete]], see ECMA-262 5th edition, section
8.12.7.
+ // Implementation of [[HasProperty]], ECMA-262 5th edition, section
8.12.6.
+ static inline bool HasProperty(Handle<JSReceiver> object, Handle<Name>
name);
+ static inline bool HasLocalProperty(Handle<JSReceiver>, Handle<Name>
name);
+ static inline bool HasElement(Handle<JSReceiver> object, uint32_t index);
+ static inline bool HasLocalElement(Handle<JSReceiver> object, uint32_t
index);
+
+ // Implementation of [[Delete]], ECMA-262 5th edition, section 8.12.7.
static Handle<Object> DeleteProperty(Handle<JSReceiver> object,
Handle<Name> name,
DeleteMode mode = NORMAL_DELETION);
@@ -1993,12 +1999,6 @@
inline PropertyAttributes GetElementAttribute(uint32_t index);
inline PropertyAttributes GetLocalElementAttribute(uint32_t index);
- // Can cause a GC.
- inline bool HasProperty(Name* name);
- inline bool HasLocalProperty(Name* name);
- inline bool HasElement(uint32_t index);
- inline bool HasLocalElement(uint32_t index);
-
// Return the object's prototype (might be Heap::null_value()).
inline Object* GetPrototype();
@@ -9077,9 +9077,6 @@
// Casting.
static inline JSProxy* cast(Object* obj);
- bool HasPropertyWithHandler(Name* name);
- bool HasElementWithHandler(uint32_t index);
-
MUST_USE_RESULT MaybeObject* GetPropertyWithHandler(
Object* receiver,
Name* name);
@@ -9154,6 +9151,9 @@
Handle<Object> value,
StrictModeFlag strict_mode);
+ static bool HasPropertyWithHandler(Handle<JSProxy> proxy, Handle<Name>
name);
+ static bool HasElementWithHandler(Handle<JSProxy> proxy, uint32_t index);
+
static Handle<Object> DeletePropertyWithHandler(Handle<JSProxy> proxy,
Handle<Name> name,
DeleteMode mode);
=======================================
--- /branches/bleeding_edge/src/runtime.cc Tue Sep 17 11:01:43 2013 UTC
+++ /branches/bleeding_edge/src/runtime.cc Tue Sep 17 11:34:20 2013 UTC
@@ -2169,7 +2169,7 @@
// Declare the property by setting it to the initial value if provided,
// or undefined, and use the correct mode (e.g. READ_ONLY attribute for
// constant declarations).
- ASSERT(!object->HasLocalProperty(*name));
+ ASSERT(!JSReceiver::HasLocalProperty(object, name));
Handle<Object> value(isolate->heap()->undefined_value(), isolate);
if (*initial_value != NULL) value = initial_value;
// Declaring a const context slot is a conflicting declaration if
@@ -4787,7 +4787,7 @@
// Check if the given key is an array index.
uint32_t index;
if (key->ToArrayIndex(&index)) {
- return isolate->heap()->ToBoolean(object->HasElement(index));
+ return isolate->heap()->ToBoolean(JSReceiver::HasElement(object,
index));
}
// Convert the key to a name - possibly by calling back into JavaScript.
@@ -4802,7 +4802,7 @@
name = Handle<Name>::cast(converted);
}
- return isolate->heap()->ToBoolean(object->HasProperty(*name));
+ return isolate->heap()->ToBoolean(JSReceiver::HasProperty(object, name));
}
MaybeObject* Runtime::GetObjectPropertyOrFail(
@@ -5520,7 +5520,9 @@
static MaybeObject* HasLocalPropertyImplementation(Isolate* isolate,
Handle<JSObject> object,
Handle<Name> key) {
- if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
+ if (JSReceiver::HasLocalProperty(object, key)) {
+ return isolate->heap()->true_value();
+ }
// Handle hidden prototypes. If there's a hidden prototype above this
thing
// then we have to check it for properties, because they are supposed to
// look like they are on this object.
@@ -5580,12 +5582,12 @@
RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
- SealHandleScope shs(isolate);
+ HandleScope scope(isolate);
ASSERT(args.length() == 2);
- CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
- CONVERT_ARG_CHECKED(Name, key, 1);
+ CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
+ CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
- bool result = receiver->HasProperty(key);
+ bool result = JSReceiver::HasProperty(receiver, key);
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
if (isolate->has_pending_exception()) return Failure::Exception();
return isolate->heap()->ToBoolean(result);
@@ -5593,12 +5595,12 @@
RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
- SealHandleScope shs(isolate);
+ HandleScope scope(isolate);
ASSERT(args.length() == 2);
- CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
+ CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
CONVERT_SMI_ARG_CHECKED(index, 1);
- bool result = receiver->HasElement(index);
+ bool result = JSReceiver::HasElement(receiver, index);
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
if (isolate->has_pending_exception()) return Failure::Exception();
return isolate->heap()->ToBoolean(result);
@@ -9209,7 +9211,7 @@
// property from it.
if (!holder.is_null()) {
Handle<JSReceiver> object = Handle<JSReceiver>::cast(holder);
- ASSERT(object->IsJSProxy() || object->HasProperty(*name));
+ ASSERT(object->IsJSProxy() || JSReceiver::HasProperty(object, name));
// GetProperty below can cause GC.
Handle<Object> receiver_handle(
object->IsGlobalObject()
@@ -10190,7 +10192,7 @@
Handle<Object> element_value(elements->get(j), isolate);
if (!element_value->IsTheHole()) {
visitor->visit(j, element_value);
- } else if (receiver->HasElement(j)) {
+ } else if (JSReceiver::HasElement(receiver, j)) {
// Call GetElement on receiver, not its prototype, or getters
won't
// have the correct receiver.
element_value = Object::GetElement(isolate, receiver, j);
@@ -10215,7 +10217,7 @@
Handle<Object> element_value =
isolate->factory()->NewNumber(double_value);
visitor->visit(j, element_value);
- } else if (receiver->HasElement(j)) {
+ } else if (JSReceiver::HasElement(receiver, j)) {
// Call GetElement on receiver, not its prototype, or getters
won't
// have the correct receiver.
Handle<Object> element_value =
@@ -11531,7 +11533,7 @@
!function_context->IsNativeContext()) {
Handle<JSObject>
ext(JSObject::cast(function_context->extension()));
- if (ext->HasProperty(*variable_name)) {
+ if (JSReceiver::HasProperty(ext, variable_name)) {
// We don't expect this to do anything except replacing
// property value.
SetProperty(isolate,
@@ -11619,7 +11621,7 @@
// be variables introduced by eval.
if (context->has_extension()) {
Handle<JSObject> ext(JSObject::cast(context->extension()));
- if (ext->HasProperty(*variable_name)) {
+ if (JSReceiver::HasProperty(ext, variable_name)) {
// We don't expect this to do anything except replacing property
value.
SetProperty(isolate,
ext,
@@ -12662,7 +12664,8 @@
// Do not materialize the arguments object for eval or top-level code.
// Skip if "arguments" is already taken.
if (!function->shared()->is_function() ||
- target->HasLocalProperty(isolate->heap()->arguments_string())) {
+ JSReceiver::HasLocalProperty(target,
+
isolate->factory()->arguments_string())) {
return target;
}
=======================================
--- /branches/bleeding_edge/test/cctest/test-heap.cc Tue Sep 17 11:01:43
2013 UTC
+++ /branches/bleeding_edge/test/cctest/test-heap.cc Tue Sep 17 11:34:20
2013 UTC
@@ -209,10 +209,9 @@
CHECK(s->IsString());
CHECK_EQ(10, s->length());
- String* object_string = String::cast(heap->Object_string());
- CHECK(
- Isolate::Current()->context()->global_object()->HasLocalProperty(
- object_string));
+ Handle<String> object_string =
Handle<String>::cast(factory->Object_string());
+ Handle<GlobalObject>
global(Isolate::Current()->context()->global_object());
+ CHECK(JSReceiver::HasLocalProperty(global, object_string));
// Check ToString for oddballs
CheckOddball(isolate, heap->true_value(), "true");
@@ -258,6 +257,7 @@
// Check GC.
heap->CollectGarbage(NEW_SPACE);
+ Handle<GlobalObject>
global(Isolate::Current()->context()->global_object());
Handle<String> name = factory->InternalizeUtf8String("theFunction");
Handle<String> prop_name = factory->InternalizeUtf8String("theSlot");
Handle<String> prop_namex = factory->InternalizeUtf8String("theSlotx");
@@ -273,7 +273,6 @@
Handle<Map> initial_map =
factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
function->set_initial_map(*initial_map);
- Handle<GlobalObject>
global(Isolate::Current()->context()->global_object());
JSReceiver::SetProperty(global, name, function, NONE, kNonStrictMode);
// Allocate an object. Unrooted after leaving the scope.
Handle<JSObject> obj = factory->NewJSObject(function);
@@ -287,8 +286,7 @@
heap->CollectGarbage(NEW_SPACE);
// Function should be alive.
- CHECK(Isolate::Current()->context()->global_object()->
- HasLocalProperty(*name));
+ CHECK(JSReceiver::HasLocalProperty(global, name));
// Check function is retained.
Object* func_value = Isolate::Current()->context()->global_object()->
GetProperty(*name)->ToObjectChecked();
@@ -299,7 +297,6 @@
HandleScope inner_scope(isolate);
// Allocate another object, make it reachable from global.
Handle<JSObject> obj = factory->NewJSObject(function);
- Handle<GlobalObject>
global(Isolate::Current()->context()->global_object());
JSReceiver::SetProperty(global, obj_name, obj, NONE, kNonStrictMode);
JSReceiver::SetProperty(obj, prop_name, twenty_three, NONE,
kNonStrictMode);
}
@@ -307,8 +304,7 @@
// After gc, it should survive.
heap->CollectGarbage(NEW_SPACE);
- CHECK(Isolate::Current()->context()->global_object()->
- HasLocalProperty(*obj_name));
+ CHECK(JSReceiver::HasLocalProperty(global, obj_name));
CHECK(Isolate::Current()->context()->global_object()->
GetProperty(*obj_name)->ToObjectChecked()->IsJSObject());
Object* obj = Isolate::Current()->context()->global_object()->
@@ -660,55 +656,55 @@
Handle<Smi> two(Smi::FromInt(2), isolate);
// check for empty
- CHECK(!obj->HasLocalProperty(*first));
+ CHECK(!JSReceiver::HasLocalProperty(obj, first));
// add first
JSReceiver::SetProperty(obj, first, one, NONE, kNonStrictMode);
- CHECK(obj->HasLocalProperty(*first));
+ CHECK(JSReceiver::HasLocalProperty(obj, first));
// delete first
JSReceiver::DeleteProperty(obj, first, JSReceiver::NORMAL_DELETION);
- CHECK(!obj->HasLocalProperty(*first));
+ CHECK(!JSReceiver::HasLocalProperty(obj, first));
// add first and then second
JSReceiver::SetProperty(obj, first, one, NONE, kNonStrictMode);
JSReceiver::SetProperty(obj, second, two, NONE, kNonStrictMode);
- CHECK(obj->HasLocalProperty(*first));
- CHECK(obj->HasLocalProperty(*second));
+ CHECK(JSReceiver::HasLocalProperty(obj, first));
+ CHECK(JSReceiver::HasLocalProperty(obj, second));
// delete first and then second
JSReceiver::DeleteProperty(obj, first, JSReceiver::NORMAL_DELETION);
- CHECK(obj->HasLocalProperty(*second));
+ CHECK(JSReceiver::HasLocalProperty(obj, second));
JSReceiver::DeleteProperty(obj, second, JSReceiver::NORMAL_DELETION);
- CHECK(!obj->HasLocalProperty(*first));
- CHECK(!obj->HasLocalProperty(*second));
+ CHECK(!JSReceiver::HasLocalProperty(obj, first));
+ CHECK(!JSReceiver::HasLocalProperty(obj, second));
// add first and then second
JSReceiver::SetProperty(obj, first, one, NONE, kNonStrictMode);
JSReceiver::SetProperty(obj, second, two, NONE, kNonStrictMode);
- CHECK(obj->HasLocalProperty(*first));
- CHECK(obj->HasLocalProperty(*second));
+ CHECK(JSReceiver::HasLocalProperty(obj, first));
+ CHECK(JSReceiver::HasLocalProperty(obj, second));
// delete second and then first
JSReceiver::DeleteProperty(obj, second, JSReceiver::NORMAL_DELETION);
- CHECK(obj->HasLocalProperty(*first));
+ CHECK(JSReceiver::HasLocalProperty(obj, first));
JSReceiver::DeleteProperty(obj, first, JSReceiver::NORMAL_DELETION);
- CHECK(!obj->HasLocalProperty(*first));
- CHECK(!obj->HasLocalProperty(*second));
+ CHECK(!JSReceiver::HasLocalProperty(obj, first));
+ CHECK(!JSReceiver::HasLocalProperty(obj, second));
// check string and internalized string match
const char* string1 = "fisk";
Handle<String> s1 = factory->NewStringFromAscii(CStrVector(string1));
JSReceiver::SetProperty(obj, s1, one, NONE, kNonStrictMode);
Handle<String> s1_string = factory->InternalizeUtf8String(string1);
- CHECK(obj->HasLocalProperty(*s1_string));
+ CHECK(JSReceiver::HasLocalProperty(obj, s1_string));
// check internalized string and string match
const char* string2 = "fugl";
Handle<String> s2_string = factory->InternalizeUtf8String(string2);
JSReceiver::SetProperty(obj, s2_string, one, NONE, kNonStrictMode);
Handle<String> s2 = factory->NewStringFromAscii(CStrVector(string2));
- CHECK(obj->HasLocalProperty(*s2));
+ CHECK(JSReceiver::HasLocalProperty(obj, s2));
}
=======================================
--- /branches/bleeding_edge/test/cctest/test-mark-compact.cc Tue Sep 17
11:01:43 2013 UTC
+++ /branches/bleeding_edge/test/cctest/test-mark-compact.cc Tue Sep 17
11:34:20 2013 UTC
@@ -201,7 +201,7 @@
func_name = String::cast(
heap->InternalizeUtf8String("theFunction")->ToObjectChecked());
- CHECK(isolate->context()->global_object()->HasLocalProperty(func_name));
+ CHECK(JSReceiver::HasLocalProperty(global, handle(func_name)));
Object* func_value = isolate->context()->global_object()->
GetProperty(func_name)->ToObjectChecked();
CHECK(func_value->IsJSFunction());
@@ -222,7 +222,7 @@
obj_name =
String::cast(heap->InternalizeUtf8String("theObject")->ToObjectChecked());
- CHECK(isolate->context()->global_object()->HasLocalProperty(obj_name));
+ CHECK(JSReceiver::HasLocalProperty(global, handle(obj_name)));
CHECK(isolate->context()->global_object()->
GetProperty(obj_name)->ToObjectChecked()->IsJSObject());
obj = JSObject::cast(isolate->context()->global_object()->
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.