Permalink
Browse files

Add auto-increment keys

When no key is explicitely yielded PHP will used auto-incrementing keys
as a fallback. They behave the same as with arrays, i.e. the key is the
successor of the largest previously used integer key.
  • Loading branch information...
1 parent bc08c2c commit 879016023566ce162be1d81e973bde9db76dd519 @nikic nikic committed May 30, 2012
Showing with 313 additions and 78 deletions.
  1. +22 −0 Zend/tests/generators/auto_incrementing_keys.phpt
  2. +3 −0 Zend/zend_generators.c
  3. +2 −0 Zend/zend_generators.h
  4. +11 −3 Zend/zend_vm_def.h
  5. +275 −75 Zend/zend_vm_execute.h
View
22 Zend/tests/generators/auto_incrementing_keys.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Generator keys are auto-incrementing by default
+--FILE--
+<?php
+
+function *gen() {
+ yield 'foo';
+ yield 'bar';
+ yield 5 => 'rab';
+ yield 'oof';
+}
+
+foreach (gen() as $k => $v) {
+ echo $k, ' => ', $v, "\n";
+}
+
+?>
+--EXPECT--
+0 => foo
+1 => bar
+5 => rab
+6 => oof
View
3 Zend/zend_generators.c
@@ -116,6 +116,9 @@ static zend_object_value zend_generator_create(zend_class_entry *class_type TSRM
generator = emalloc(sizeof(zend_generator));
memset(generator, 0, sizeof(zend_generator));
+ /* The key will be incremented on first use, so it'll start at 0 */
+ generator->largest_used_integer_key = -1;
+
zend_object_std_init(&generator->std, class_type TSRMLS_CC);
object.handle = zend_objects_store_put(generator, NULL,
View
2 Zend/zend_generators.h
@@ -34,6 +34,8 @@ typedef struct _zend_generator {
zval *key;
/* Variable to put sent value into */
temp_variable *send_target;
+ /* Largest used integer key for auto-incrementing keys */
+ long largest_used_integer_key;
} zend_generator;
extern ZEND_API zend_class_entry *zend_ce_generator;
View
14 Zend/zend_vm_def.h
@@ -5332,11 +5332,19 @@ ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSE
generator->key = key;
}
+ if (Z_TYPE_P(generator->key) == IS_LONG
+ && Z_LVAL_P(generator->key) > generator->largest_used_integer_key
+ ) {
+ generator->largest_used_integer_key = Z_LVAL_P(generator->key);
+ }
+
FREE_OP2_IF_VAR();
} else {
- /* Setting the key to NULL signals that the auto-increment key
- * generation should be used */
- generator->key = NULL;
+ /* If no key was specified we use auto-increment keys */
+ generator->largest_used_integer_key++;
+
+ ALLOC_INIT_ZVAL(generator->key);
+ ZVAL_LONG(generator->key, generator->largest_used_integer_key);
}
/* If a value is sent it should go into the result var */
View
350 Zend/zend_vm_execute.h
@@ -4127,10 +4127,18 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLE
generator->key = key;
}
+ if (Z_TYPE_P(generator->key) == IS_LONG
+ && Z_LVAL_P(generator->key) > generator->largest_used_integer_key
+ ) {
+ generator->largest_used_integer_key = Z_LVAL_P(generator->key);
+ }
+
} else {
- /* Setting the key to NULL signals that the auto-increment key
- * generation should be used */
- generator->key = NULL;
+ /* If no key was specified we use auto-increment keys */
+ generator->largest_used_integer_key++;
+
+ ALLOC_INIT_ZVAL(generator->key);
+ ZVAL_LONG(generator->key, generator->largest_used_integer_key);
}
/* If a value is sent it should go into the result var */
@@ -4760,10 +4768,18 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_
generator->key = key;
}
+ if (Z_TYPE_P(generator->key) == IS_LONG
+ && Z_LVAL_P(generator->key) > generator->largest_used_integer_key
+ ) {
+ generator->largest_used_integer_key = Z_LVAL_P(generator->key);
+ }
+
} else {
- /* Setting the key to NULL signals that the auto-increment key
- * generation should be used */
- generator->key = NULL;
+ /* If no key was specified we use auto-increment keys */
+ generator->largest_used_integer_key++;
+
+ ALLOC_INIT_ZVAL(generator->key);
+ ZVAL_LONG(generator->key, generator->largest_used_integer_key);
}
/* If a value is sent it should go into the result var */
@@ -5718,11 +5734,19 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_
generator->key = key;
}
+ if (Z_TYPE_P(generator->key) == IS_LONG
+ && Z_LVAL_P(generator->key) > generator->largest_used_integer_key
+ ) {
+ generator->largest_used_integer_key = Z_LVAL_P(generator->key);
+ }
+
if (free_op2.var) {zval_ptr_dtor(&free_op2.var);};
} else {
- /* Setting the key to NULL signals that the auto-increment key
- * generation should be used */
- generator->key = NULL;
+ /* If no key was specified we use auto-increment keys */
+ generator->largest_used_integer_key++;
+
+ ALLOC_INIT_ZVAL(generator->key);
+ ZVAL_LONG(generator->key, generator->largest_used_integer_key);
}
/* If a value is sent it should go into the result var */
@@ -6371,10 +6395,18 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDL
generator->key = key;
}
+ if (Z_TYPE_P(generator->key) == IS_LONG
+ && Z_LVAL_P(generator->key) > generator->largest_used_integer_key
+ ) {
+ generator->largest_used_integer_key = Z_LVAL_P(generator->key);
+ }
+
} else {
- /* Setting the key to NULL signals that the auto-increment key
- * generation should be used */
- generator->key = NULL;
+ /* If no key was specified we use auto-increment keys */
+ generator->largest_used_integer_key++;
+
+ ALLOC_INIT_ZVAL(generator->key);
+ ZVAL_LONG(generator->key, generator->largest_used_integer_key);
}
/* If a value is sent it should go into the result var */
@@ -7063,10 +7095,18 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_A
generator->key = key;
}
+ if (Z_TYPE_P(generator->key) == IS_LONG
+ && Z_LVAL_P(generator->key) > generator->largest_used_integer_key
+ ) {
+ generator->largest_used_integer_key = Z_LVAL_P(generator->key);
+ }
+
} else {
- /* Setting the key to NULL signals that the auto-increment key
- * generation should be used */
- generator->key = NULL;
+ /* If no key was specified we use auto-increment keys */
+ generator->largest_used_integer_key++;
+
+ ALLOC_INIT_ZVAL(generator->key);
+ ZVAL_LONG(generator->key, generator->largest_used_integer_key);
}
/* If a value is sent it should go into the result var */
@@ -9058,10 +9098,18 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_
generator->key = key;
}
+ if (Z_TYPE_P(generator->key) == IS_LONG
+ && Z_LVAL_P(generator->key) > generator->largest_used_integer_key
+ ) {
+ generator->largest_used_integer_key = Z_LVAL_P(generator->key);
+ }
+
} else {
- /* Setting the key to NULL signals that the auto-increment key
- * generation should be used */
- generator->key = NULL;
+ /* If no key was specified we use auto-increment keys */
+ generator->largest_used_integer_key++;
+
+ ALLOC_INIT_ZVAL(generator->key);
+ ZVAL_LONG(generator->key, generator->largest_used_integer_key);
}
/* If a value is sent it should go into the result var */
@@ -9691,10 +9739,18 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR
generator->key = key;
}
+ if (Z_TYPE_P(generator->key) == IS_LONG
+ && Z_LVAL_P(generator->key) > generator->largest_used_integer_key
+ ) {
+ generator->largest_used_integer_key = Z_LVAL_P(generator->key);
+ }
+
} else {
- /* Setting the key to NULL signals that the auto-increment key
- * generation should be used */
- generator->key = NULL;
+ /* If no key was specified we use auto-increment keys */
+ generator->largest_used_integer_key++;
+
+ ALLOC_INIT_ZVAL(generator->key);
+ ZVAL_LONG(generator->key, generator->largest_used_integer_key);
}
/* If a value is sent it should go into the result var */
@@ -10649,11 +10705,19 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR
generator->key = key;
}
+ if (Z_TYPE_P(generator->key) == IS_LONG
+ && Z_LVAL_P(generator->key) > generator->largest_used_integer_key
+ ) {
+ generator->largest_used_integer_key = Z_LVAL_P(generator->key);
+ }
+
if (free_op2.var) {zval_ptr_dtor(&free_op2.var);};
} else {
- /* Setting the key to NULL signals that the auto-increment key
- * generation should be used */
- generator->key = NULL;
+ /* If no key was specified we use auto-increment keys */
+ generator->largest_used_integer_key++;
+
+ ALLOC_INIT_ZVAL(generator->key);
+ ZVAL_LONG(generator->key, generator->largest_used_integer_key);
}
/* If a value is sent it should go into the result var */
@@ -11168,10 +11232,18 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCODE_HANDLER
generator->key = key;
}
+ if (Z_TYPE_P(generator->key) == IS_LONG
+ && Z_LVAL_P(generator->key) > generator->largest_used_integer_key
+ ) {
+ generator->largest_used_integer_key = Z_LVAL_P(generator->key);
+ }
+
} else {
- /* Setting the key to NULL signals that the auto-increment key
- * generation should be used */
- generator->key = NULL;
+ /* If no key was specified we use auto-increment keys */
+ generator->largest_used_integer_key++;
+
+ ALLOC_INIT_ZVAL(generator->key);
+ ZVAL_LONG(generator->key, generator->largest_used_integer_key);
}
/* If a value is sent it should go into the result var */
@@ -11798,10 +11870,18 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG
generator->key = key;
}
+ if (Z_TYPE_P(generator->key) == IS_LONG
+ && Z_LVAL_P(generator->key) > generator->largest_used_integer_key
+ ) {
+ generator->largest_used_integer_key = Z_LVAL_P(generator->key);
+ }
+
} else {
- /* Setting the key to NULL signals that the auto-increment key
- * generation should be used */
- generator->key = NULL;
+ /* If no key was specified we use auto-increment keys */
+ generator->largest_used_integer_key++;
+
+ ALLOC_INIT_ZVAL(generator->key);
+ ZVAL_LONG(generator->key, generator->largest_used_integer_key);
}
/* If a value is sent it should go into the result var */
@@ -15650,10 +15730,18 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_
generator->key = key;
}
+ if (Z_TYPE_P(generator->key) == IS_LONG
+ && Z_LVAL_P(generator->key) > generator->largest_used_integer_key
+ ) {
+ generator->largest_used_integer_key = Z_LVAL_P(generator->key);
+ }
+
} else {
- /* Setting the key to NULL signals that the auto-increment key
- * generation should be used */
- generator->key = NULL;
+ /* If no key was specified we use auto-increment keys */
+ generator->largest_used_integer_key++;
+
+ ALLOC_INIT_ZVAL(generator->key);
+ ZVAL_LONG(generator->key, generator->largest_used_integer_key);
}
/* If a value is sent it should go into the result var */
@@ -17670,10 +17758,18 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR
generator->key = key;
}
+ if (Z_TYPE_P(generator->key) == IS_LONG
+ && Z_LVAL_P(generator->key) > generator->largest_used_integer_key
+ ) {
+ generator->largest_used_integer_key = Z_LVAL_P(generator->key);
+ }
+
} else {
- /* Setting the key to NULL signals that the auto-increment key
- * generation should be used */
- generator->key = NULL;
+ /* If no key was specified we use auto-increment keys */
+ generator->largest_used_integer_key++;
+
+ ALLOC_INIT_ZVAL(generator->key);
+ ZVAL_LONG(generator->key, generator->largest_used_integer_key);
}
/* If a value is sent it should go into the result var */
@@ -20070,11 +20166,19 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR
generator->key = key;
}
+ if (Z_TYPE_P(generator->key) == IS_LONG
+ && Z_LVAL_P(generator->key) > generator->largest_used_integer_key
+ ) {
+ generator->largest_used_integer_key = Z_LVAL_P(generator->key);
+ }
+
if (free_op2.var) {zval_ptr_dtor(&free_op2.var);};
} else {
- /* Setting the key to NULL signals that the auto-increment key
- * generation should be used */
- generator->key = NULL;
+ /* If no key was specified we use auto-increment keys */
+ generator->largest_used_integer_key++;
+
+ ALLOC_INIT_ZVAL(generator->key);
+ ZVAL_LONG(generator->key, generator->largest_used_integer_key);
}
/* If a value is sent it should go into the result var */
@@ -21149,10 +21253,18 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER
generator->key = key;
}
+ if (Z_TYPE_P(generator->key) == IS_LONG
+ && Z_LVAL_P(generator->key) > generator->largest_used_integer_key
+ ) {
+ generator->largest_used_integer_key = Z_LVAL_P(generator->key);
+ }
+
} else {
- /* Setting the key to NULL signals that the auto-increment key
- * generation should be used */
- generator->key = NULL;
+ /* If no key was specified we use auto-increment keys */
+ generator->largest_used_integer_key++;
+
+ ALLOC_INIT_ZVAL(generator->key);
+ ZVAL_LONG(generator->key, generator->largest_used_integer_key);
}
/* If a value is sent it should go into the result var */
@@ -23218,10 +23330,18 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG
generator->key = key;
}
+ if (Z_TYPE_P(generator->key) == IS_LONG
+ && Z_LVAL_P(generator->key) > generator->largest_used_integer_key
+ ) {
+ generator->largest_used_integer_key = Z_LVAL_P(generator->key);
+ }
+
} else {
- /* Setting the key to NULL signals that the auto-increment key
- * generation should be used */
- generator->key = NULL;
+ /* If no key was specified we use auto-increment keys */
+ generator->largest_used_integer_key++;
+
+ ALLOC_INIT_ZVAL(generator->key);
+ ZVAL_LONG(generator->key, generator->largest_used_integer_key);
}
/* If a value is sent it should go into the result var */
@@ -24645,10 +24765,18 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDL
generator->key = key;
}
+ if (Z_TYPE_P(generator->key) == IS_LONG
+ && Z_LVAL_P(generator->key) > generator->largest_used_integer_key
+ ) {
+ generator->largest_used_integer_key = Z_LVAL_P(generator->key);
+ }
+
} else {
- /* Setting the key to NULL signals that the auto-increment key
- * generation should be used */
- generator->key = NULL;
+ /* If no key was specified we use auto-increment keys */
+ generator->largest_used_integer_key++;
+
+ ALLOC_INIT_ZVAL(generator->key);
+ ZVAL_LONG(generator->key, generator->largest_used_integer_key);
}
/* If a value is sent it should go into the result var */
@@ -25896,10 +26024,18 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER
generator->key = key;
}
+ if (Z_TYPE_P(generator->key) == IS_LONG
+ && Z_LVAL_P(generator->key) > generator->largest_used_integer_key
+ ) {
+ generator->largest_used_integer_key = Z_LVAL_P(generator->key);
+ }
+
} else {
- /* Setting the key to NULL signals that the auto-increment key
- * generation should be used */
- generator->key = NULL;
+ /* If no key was specified we use auto-increment keys */
+ generator->largest_used_integer_key++;
+
+ ALLOC_INIT_ZVAL(generator->key);
+ ZVAL_LONG(generator->key, generator->largest_used_integer_key);
}
/* If a value is sent it should go into the result var */
@@ -27147,11 +27283,19 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER
generator->key = key;
}
+ if (Z_TYPE_P(generator->key) == IS_LONG
+ && Z_LVAL_P(generator->key) > generator->largest_used_integer_key
+ ) {
+ generator->largest_used_integer_key = Z_LVAL_P(generator->key);
+ }
+
if (free_op2.var) {zval_ptr_dtor(&free_op2.var);};
} else {
- /* Setting the key to NULL signals that the auto-increment key
- * generation should be used */
- generator->key = NULL;
+ /* If no key was specified we use auto-increment keys */
+ generator->largest_used_integer_key++;
+
+ ALLOC_INIT_ZVAL(generator->key);
+ ZVAL_LONG(generator->key, generator->largest_used_integer_key);
}
/* If a value is sent it should go into the result var */
@@ -27510,10 +27654,18 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HAND
generator->key = key;
}
+ if (Z_TYPE_P(generator->key) == IS_LONG
+ && Z_LVAL_P(generator->key) > generator->largest_used_integer_key
+ ) {
+ generator->largest_used_integer_key = Z_LVAL_P(generator->key);
+ }
+
} else {
- /* Setting the key to NULL signals that the auto-increment key
- * generation should be used */
- generator->key = NULL;
+ /* If no key was specified we use auto-increment keys */
+ generator->largest_used_integer_key++;
+
+ ALLOC_INIT_ZVAL(generator->key);
+ ZVAL_LONG(generator->key, generator->largest_used_integer_key);
}
/* If a value is sent it should go into the result var */
@@ -28758,10 +28910,18 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_
generator->key = key;
}
+ if (Z_TYPE_P(generator->key) == IS_LONG
+ && Z_LVAL_P(generator->key) > generator->largest_used_integer_key
+ ) {
+ generator->largest_used_integer_key = Z_LVAL_P(generator->key);
+ }
+
} else {
- /* Setting the key to NULL signals that the auto-increment key
- * generation should be used */
- generator->key = NULL;
+ /* If no key was specified we use auto-increment keys */
+ generator->largest_used_integer_key++;
+
+ ALLOC_INIT_ZVAL(generator->key);
+ ZVAL_LONG(generator->key, generator->largest_used_integer_key);
}
/* If a value is sent it should go into the result var */
@@ -32210,10 +32370,18 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_A
generator->key = key;
}
+ if (Z_TYPE_P(generator->key) == IS_LONG
+ && Z_LVAL_P(generator->key) > generator->largest_used_integer_key
+ ) {
+ generator->largest_used_integer_key = Z_LVAL_P(generator->key);
+ }
+
} else {
- /* Setting the key to NULL signals that the auto-increment key
- * generation should be used */
- generator->key = NULL;
+ /* If no key was specified we use auto-increment keys */
+ generator->largest_used_integer_key++;
+
+ ALLOC_INIT_ZVAL(generator->key);
+ ZVAL_LONG(generator->key, generator->largest_used_integer_key);
}
/* If a value is sent it should go into the result var */
@@ -34100,10 +34268,18 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG
generator->key = key;
}
+ if (Z_TYPE_P(generator->key) == IS_LONG
+ && Z_LVAL_P(generator->key) > generator->largest_used_integer_key
+ ) {
+ generator->largest_used_integer_key = Z_LVAL_P(generator->key);
+ }
+
} else {
- /* Setting the key to NULL signals that the auto-increment key
- * generation should be used */
- generator->key = NULL;
+ /* If no key was specified we use auto-increment keys */
+ generator->largest_used_integer_key++;
+
+ ALLOC_INIT_ZVAL(generator->key);
+ ZVAL_LONG(generator->key, generator->largest_used_integer_key);
}
/* If a value is sent it should go into the result var */
@@ -36369,11 +36545,19 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG
generator->key = key;
}
+ if (Z_TYPE_P(generator->key) == IS_LONG
+ && Z_LVAL_P(generator->key) > generator->largest_used_integer_key
+ ) {
+ generator->largest_used_integer_key = Z_LVAL_P(generator->key);
+ }
+
if (free_op2.var) {zval_ptr_dtor(&free_op2.var);};
} else {
- /* Setting the key to NULL signals that the auto-increment key
- * generation should be used */
- generator->key = NULL;
+ /* If no key was specified we use auto-increment keys */
+ generator->largest_used_integer_key++;
+
+ ALLOC_INIT_ZVAL(generator->key);
+ ZVAL_LONG(generator->key, generator->largest_used_integer_key);
}
/* If a value is sent it should go into the result var */
@@ -37308,10 +37492,18 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_
generator->key = key;
}
+ if (Z_TYPE_P(generator->key) == IS_LONG
+ && Z_LVAL_P(generator->key) > generator->largest_used_integer_key
+ ) {
+ generator->largest_used_integer_key = Z_LVAL_P(generator->key);
+ }
+
} else {
- /* Setting the key to NULL signals that the auto-increment key
- * generation should be used */
- generator->key = NULL;
+ /* If no key was specified we use auto-increment keys */
+ generator->largest_used_integer_key++;
+
+ ALLOC_INIT_ZVAL(generator->key);
+ ZVAL_LONG(generator->key, generator->largest_used_integer_key);
}
/* If a value is sent it should go into the result var */
@@ -39246,10 +39438,18 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS
generator->key = key;
}
+ if (Z_TYPE_P(generator->key) == IS_LONG
+ && Z_LVAL_P(generator->key) > generator->largest_used_integer_key
+ ) {
+ generator->largest_used_integer_key = Z_LVAL_P(generator->key);
+ }
+
} else {
- /* Setting the key to NULL signals that the auto-increment key
- * generation should be used */
- generator->key = NULL;
+ /* If no key was specified we use auto-increment keys */
+ generator->largest_used_integer_key++;
+
+ ALLOC_INIT_ZVAL(generator->key);
+ ZVAL_LONG(generator->key, generator->largest_used_integer_key);
}
/* If a value is sent it should go into the result var */

0 comments on commit 8790160

Please sign in to comment.