Difference between revisions of "Category talk:LSL Vector"

From Second Life Wiki
Jump to navigation Jump to search
(Created page with "//******************************* //IMPOSSIBLE TO GET A ZERO_VECTOR //******************************* vector c = <0.0, 0.0, 0.1>; default { touch_start(integer total_number…")
 
 
(10 intermediate revisions by 3 users not shown)
Line 1: Line 1:
<lsl>
//*******************************
//*******************************
//IMPOSSIBLE TO GET A ZERO_VECTOR
//IMPOSSIBLE TO GET A ZERO_VECTOR
Line 14: Line 15:
     }
     }
}
}
 
</lsl>
 
<lsl>
//**********************
//**********************
//IN THIS WAY IT RUNS...
//IN THIS WAY IT RUNS...
Line 32: Line 33:
     }
     }
}
}
</lsl>
{{unsigned|Zohan Galewind|06:29, 29 April 2012}}
----
The above is caused by how floating point math works. 0.1 does not fall on an exact boundary as a float, nor does 0.025. Furthermore the rounding on the two values do not exactly line up, so (4 * 0.025) != 0.1. This is not a bug but a caveat of using floating point math. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 11:00, 29 April 2012 (PDT)
===Useful Snippets===
The IsVector function fails for vectors whose z element is negative, at least under Mono. (It also does not work on other grids because the cast to vector and back to string eliminates negative zero there.)<br>
'''Edit:''' It does work, see Correction below...
I tried the following:
<lsl>
// After the "->" is the expected result (for the proposed new function), after the ":" the actual one
llOwnerSay( "IsVector(<0.47,0.149, 1.001>) -> 1: "              + (string)IsVector( "<0.47,0.149, 1.001>" ) );
llOwnerSay( "IsVector(<0.47,0.149, 1.001,3>) -> 0: "            + (string)IsVector( "<0.47,0.149, 1.001,3>" ) );
llOwnerSay( "IsVector(<0.47,0.149,-1.001>) -> 1: "              + (string)IsVector( "<0.47,0.149,-1.001>" ) );
llOwnerSay( "IsVector(<0.47,0.149,+1.001>) -> 1: "              + (string)IsVector( "<0.47,0.149,+1.001>" ) );
llOwnerSay( "IsVector(  <  0.47, 0.149,    -1.001  > ) -> 0: " + (string)IsVector( "  <  0.47, 0.149,    -1.001  > " ) );
llOwnerSay( "IsVector(<0.47,0.1A9,-1.001>) -> 0: "              + (string)IsVector( "<0.47,0.1A9,-1.001>" ) );
llOwnerSay( "IsVector(<0.47,;0.149,-1.001>) -> 0: "              + (string)IsVector( "<0.47,;0.149,-1.001>" ) );
llOwnerSay( "IsVector(<0.47,0.149,-1.001) -> 1: "                + (string)IsVector( "<0.47,0.149,-1.001" ) );
llOwnerSay( "IsVector(<0,0.000,0>) -> 1: "                      + (string)IsVector( "<0,0.000,0>" ) );
llOwnerSay( "IsVector(<0,0.000,0,0>) -> 0: "                    + (string)IsVector( "<0,0.000,0,0>" ) );
llOwnerSay( "IsVector(<+0,-0.000,-0>) -> 1: "                    + (string)IsVector( "<+0,-0.000,-0>" ) );
</lsl>
I propose the following change:
<lsl>
// Returns whether the given string contains a vector.
// Accepts what the compiler accepts and checks ZERO_VECTOR separately.
integer IsVector ( string s )
{
    list split = llParseString2List( s, ["<", ">", ",", " ", "-", "+"], [] );  // not allowed to be inside numbers
    if ( llGetListLength( split ) != 3 ) return FALSE;  // must be 3 elements
    if ( (vector)s != ZERO_VECTOR ) return TRUE;  // parsing error or real ZERO_VECTOR lead to ZERO_VECTOR
    split = llParseString2List( (string)split, ["0", "."], [] );
    return (split == []);
}
</lsl>
With this function, the above tests work. It tests for number of elements and then lets the compiler decide what it accepts as vector. Only for ZERO_VECTOR, special treatment is necessary. Therefore, it checks that only zeros and decimal points are in the remaining string. The compiler itself accepts missing ">" and it would also accept more than 3 elements - that's why the function checks the number of elements before.
It's probably not the most efficient way to do it and also accepts more than is actually valid (esp. for ZERO_VECTOR), but it does accept all valid vectors (I hope ^^). Discussion and improvements are welcome. For IsRotation, the implementation would be almost the same, except checking for 4 elements instead of 3.
[[User:Shuichi Shinji|Shuichi Shinji]] 01:13, 31 March 2014 (PDT)
:It's going to give false positives on things with multiple periods. And it doesn't handle zero vectors expressed in hex or scientific notation. I applaud your efforts thus far. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 13:16, 31 March 2014 (PDT)
<lsl>
llOwnerSay( "IsVector(<.,.,.>) -> 0: "                          + (string)IsVector( "<.,.,.>" ) );//BTW: breaks LSL Editor
llOwnerSay( "IsVector(<.......,0,0>) -> 0: "                    + (string)IsVector( "<.......,0,0>" ) );//BTW: breaks LSL Editor
llOwnerSay( "IsVector(<0x0.0,0x0p+1,-0x0p-1>) -> 1: "            + (string)IsVector( "<0x0.0,0x0.p+1,-0x0.p-1>" ) );
llOwnerSay( "IsVector(<0.0e1,0.0e+1,-0.0e-1>) -> 1: "            + (string)IsVector( "<0.0e1,0.0e+1,-0.0e-1>" ) );
</lsl>
::Right. I don't know how bad false positives are; the other 2 could be solved by adding 1,x,e,p to the split list, but also adding more false positives, which is not nice. But just adding a "-" to the split list in the original implementation would solve that it's not working for negative z's yet. Of course, it would also add some false positives, such as "1.2--3", but so it already did with "1.2  3" (spaces inside the number) - maybe one line from my proposal could be added so that it properly checks non-ZERO_VECTORs, at least. -- [[User:Shuichi Shinji|Shuichi Shinji]] 08:30, 4 April 2014 (PDT)
<lsl>
integer IsVector(string s)
{
    list split = llParseString2List(s, [" ", "-"], ["<", ">", ","]);
    if(llGetListLength(split) != 7)//we must check the list length, or the next test won't work properly.
        return FALSE;
    if((vector)s != ZERO_VECTOR)//parsing error or real ZERO_VECTOR lead to ZERO_VECTOR
        return TRUE;
    return !((string)((vector)s) == (string)((vector)((string)llListInsertList(split, ["-"], 5))));
    //it works by trying to flip the sign on the Z element of the vector,
    //if it works or breaks the vector then the values won't match.
    //if the vector was already broken then the sign flip will have no affect and the values will match
    //we cast back to string so we can catch negative zero which allows for support of ZERO_VECTOR
}
</lsl>
----
====Correction====
Ok, your function '''does''' work for negative z's, I must have made a mistake when I first checked it - sorry for the confusion. However, I have a few improvements:
* don't filter out spaces during the split, because e.g. "  < 1 , 2 , 3 > " is not a valid vector (the leading spaces are the problem): <lsl>list split = llParseString2List( s, [], ["<", ">", ","] );</lsl>
* for rotations, don't add the "-" for the s member, but for z (I had problems with s)
With these, the following checks all work (in SL; LSLeditor interprets it a bit differently in some cases):
<lsl>
llOwnerSay( "IsVector(<0.47,0.149, 1.001>) -> 1: "              + (string)IsVector( "<0.47,0.149, 1.001>" ) );
llOwnerSay( "IsVector(<0.47,0.149, 1.001,3>) -> 0: "            + (string)IsVector( "<0.47,0.149, 1.001,3>" ) );
llOwnerSay( "IsVector(<0.47,0.149,-1.001>) -> 1: "              + (string)IsVector( "<0.47,0.149,-1.001>" ) );
llOwnerSay( "IsVector(<0.47,0.149,+1.001>) -> 1: "              + (string)IsVector( "<0.47,0.149,+1.001>" ) );
llOwnerSay( "IsVector(<  0.47, 0.149,    -1.001  >) -> 1: "    + (string)IsVector( "<  0.47, 0.149,    -1.001  >" ) );
llOwnerSay( "IsVector(  <  0.47, 0.149,    -1.001  > ) -> 0: " + (string)IsVector( "  <  0.47, 0.149,    -1.001  > " ) );
llOwnerSay( "IsVector(<0.47,0.1A9,-1.001>) -> 0: "              + (string)IsVector( "<0.47,0.1A9,-1.001>" ) );
llOwnerSay( "IsVector(<0.47,0.149,;-1.001>) -> 0: "              + (string)IsVector( "<0.47,;0.149,-1.001>" ) );
llOwnerSay( "IsVector(<0.47,0.149,-1.001) -> 0: "                + (string)IsVector( "<0.47,0.149,-1.001" ) );
llOwnerSay( "IsVector(<0,0.000,0>) -> 1: "                      + (string)IsVector( "<0,0.000,0>" ) );
llOwnerSay( "IsVector(<0,0.000,0,0>) -> 0: "                    + (string)IsVector( "<0,0.000,0,0>" ) );
llOwnerSay( "IsVector(<+0,-0.000,-0>) -> 1: "                    + (string)IsVector( "<+0,-0.000,-0>" ) );
llOwnerSay( "IsVector(<0x0.0,0x0p+1,-0x0p-1>) -> 1: "            + (string)IsVector( "<0x0.0,0x0.p+1,-0x0.p-1>" ) );
llOwnerSay( "IsVector(<0.0e1,0.0e+1,-0.0e-1>) -> 1: "            + (string)IsVector( "<0.0e1,0.0e+1,-0.0e-1>" ) );
llOwnerSay( "IsRotation(<0.47,0.149,-1.001>) -> 0: "            + (string)IsRotation( "<0.47,0.149,-1.001>" ) );
llOwnerSay( "IsRotation(<0.47,0.149,-1.001,3>) -> 1: "          + (string)IsRotation( "<0.47,0.149,-1.001,3>" ) );
llOwnerSay( "IsRotation(<0.47,0.149,+1.001,3>) -> 1: "          + (string)IsRotation( "<0.47,0.149,+1.001,3>" ) );
llOwnerSay( "IsRotation(<  0.47, 0.149,  0.99,3  >) -> 1: "    + (string)IsRotation( "<  0.47, 0.149,  0.99,3  >" ) );
llOwnerSay( "IsRotation(  <  0.47, 0.149,  0.99,3  > ) -> 0: "  + (string)IsRotation( "  <  0.47, 0.149,  0.99,3  > " ) );
llOwnerSay( "IsRotation(<0.47,0.1A9,-1.001,3>) -> 0: "          + (string)IsRotation( "<0.47,0.1A9,-1.001,3>" ) );
llOwnerSay( "IsRotation(<0.47,0.149,-1.001,;3>) -> 0: "          + (string)IsRotation( "<0.47,;0.149,-1.001,3>" ) );
llOwnerSay( "IsRotation(<0.47,0.149,-1.001,3) -> 0: "            + (string)IsRotation( "<0.47,0.149,-1.001,3" ) );
llOwnerSay( "IsRotation(<0,0.000,0>) -> 0: "                    + (string)IsRotation( "<0,0.000,0>" ) );
llOwnerSay( "IsRotation(<0,0.000,0,0>) -> 1: "                  + (string)IsRotation( "<0,0.000,0,0>" ) );
llOwnerSay( "IsRotation(<+0,-0.000,-0,-0>) -> 1: "              + (string)IsRotation( "<+0,-0.000,-0,-0>" ) );
</lsl>
'''Not relevant for SL, just a remark:''' For grids where the "-" approach does not work because negative zeros are filtered out during the casts, the following slightly less elegant works instead:
<lsl>
// vector
if ( (vector)((string)llListReplaceList( split, [1], 5, 5 )) == ZERO_VECTOR ) return FALSE;  // parsing error in x or y
return ((vector)((string)llListReplaceList( split, [1], 3, 3 )) != ZERO_VECTOR);            // parsing error in z
// rotation
if ( (rotation)((string)llListReplaceList( split, [2], 7, 7 )) == ZERO_ROTATION ) return FALSE;  // parsing error in x, y or z
return ((rotation)((string)llListReplaceList( split, [1], 5, 5 )) != ZERO_ROTATION);              // parsing error in s
</lsl>
[[User:Shuichi Shinji|Shuichi Shinji]] 01:20, 10 April 2014 (PDT)

Latest revision as of 01:20, 10 April 2014

<lsl> //******************************* //IMPOSSIBLE TO GET A ZERO_VECTOR //*******************************

vector c = <0.0, 0.0, 0.1>;

default {

   touch_start(integer total_number)
   {
       c -= <0.0, 0.0, 0.025>;
       llSay(0, (string)c);
       if (c == ZERO_VECTOR) llSay(0, "ZERO_VECTOR"); // never c is a ZERO_VECTOR
   }

} </lsl> <lsl> //********************** //IN THIS WAY IT RUNS... //**********************

vector c = <0.0, 0.0, 0.1>;

default {

   touch_start(integer total_number)
   {
       c -= <0.0, 0.0, 0.025>;
       llSay(0, (string)c);
       if ((string)c == "<0.00000, 0.00000, 0.00000>") llSay(0, "ZERO_VECTOR");
   }

} </lsl> —The preceding unsigned comment was added on 06:29, 29 April 2012 by Zohan Galewind


The above is caused by how floating point math works. 0.1 does not fall on an exact boundary as a float, nor does 0.025. Furthermore the rounding on the two values do not exactly line up, so (4 * 0.025) != 0.1. This is not a bug but a caveat of using floating point math. -- Strife (talk|contribs) 11:00, 29 April 2012 (PDT)

Useful Snippets

The IsVector function fails for vectors whose z element is negative, at least under Mono. (It also does not work on other grids because the cast to vector and back to string eliminates negative zero there.)
Edit: It does work, see Correction below...

I tried the following:

<lsl> // After the "->" is the expected result (for the proposed new function), after the ":" the actual one llOwnerSay( "IsVector(<0.47,0.149, 1.001>) -> 1: " + (string)IsVector( "<0.47,0.149, 1.001>" ) ); llOwnerSay( "IsVector(<0.47,0.149, 1.001,3>) -> 0: " + (string)IsVector( "<0.47,0.149, 1.001,3>" ) ); llOwnerSay( "IsVector(<0.47,0.149,-1.001>) -> 1: " + (string)IsVector( "<0.47,0.149,-1.001>" ) ); llOwnerSay( "IsVector(<0.47,0.149,+1.001>) -> 1: " + (string)IsVector( "<0.47,0.149,+1.001>" ) ); llOwnerSay( "IsVector( < 0.47, 0.149, -1.001 > ) -> 0: " + (string)IsVector( " < 0.47, 0.149, -1.001 > " ) ); llOwnerSay( "IsVector(<0.47,0.1A9,-1.001>) -> 0: " + (string)IsVector( "<0.47,0.1A9,-1.001>" ) ); llOwnerSay( "IsVector(<0.47,;0.149,-1.001>) -> 0: " + (string)IsVector( "<0.47,;0.149,-1.001>" ) ); llOwnerSay( "IsVector(<0.47,0.149,-1.001) -> 1: " + (string)IsVector( "<0.47,0.149,-1.001" ) ); llOwnerSay( "IsVector(<0,0.000,0>) -> 1: " + (string)IsVector( "<0,0.000,0>" ) ); llOwnerSay( "IsVector(<0,0.000,0,0>) -> 0: " + (string)IsVector( "<0,0.000,0,0>" ) ); llOwnerSay( "IsVector(<+0,-0.000,-0>) -> 1: " + (string)IsVector( "<+0,-0.000,-0>" ) ); </lsl>

I propose the following change:

<lsl> // Returns whether the given string contains a vector. // Accepts what the compiler accepts and checks ZERO_VECTOR separately. integer IsVector ( string s ) {

   list split = llParseString2List( s, ["<", ">", ",", " ", "-", "+"], [] );  // not allowed to be inside numbers
   if ( llGetListLength( split ) != 3 ) return FALSE;  // must be 3 elements
   if ( (vector)s != ZERO_VECTOR ) return TRUE;  // parsing error or real ZERO_VECTOR lead to ZERO_VECTOR
   split = llParseString2List( (string)split, ["0", "."], [] );
   return (split == []);

} </lsl>

With this function, the above tests work. It tests for number of elements and then lets the compiler decide what it accepts as vector. Only for ZERO_VECTOR, special treatment is necessary. Therefore, it checks that only zeros and decimal points are in the remaining string. The compiler itself accepts missing ">" and it would also accept more than 3 elements - that's why the function checks the number of elements before.

It's probably not the most efficient way to do it and also accepts more than is actually valid (esp. for ZERO_VECTOR), but it does accept all valid vectors (I hope ^^). Discussion and improvements are welcome. For IsRotation, the implementation would be almost the same, except checking for 4 elements instead of 3.

Shuichi Shinji 01:13, 31 March 2014 (PDT)

It's going to give false positives on things with multiple periods. And it doesn't handle zero vectors expressed in hex or scientific notation. I applaud your efforts thus far. -- Strife (talk|contribs) 13:16, 31 March 2014 (PDT)

<lsl> llOwnerSay( "IsVector(<.,.,.>) -> 0: " + (string)IsVector( "<.,.,.>" ) );//BTW: breaks LSL Editor llOwnerSay( "IsVector(<.......,0,0>) -> 0: " + (string)IsVector( "<.......,0,0>" ) );//BTW: breaks LSL Editor llOwnerSay( "IsVector(<0x0.0,0x0p+1,-0x0p-1>) -> 1: " + (string)IsVector( "<0x0.0,0x0.p+1,-0x0.p-1>" ) ); llOwnerSay( "IsVector(<0.0e1,0.0e+1,-0.0e-1>) -> 1: " + (string)IsVector( "<0.0e1,0.0e+1,-0.0e-1>" ) ); </lsl>

Right. I don't know how bad false positives are; the other 2 could be solved by adding 1,x,e,p to the split list, but also adding more false positives, which is not nice. But just adding a "-" to the split list in the original implementation would solve that it's not working for negative z's yet. Of course, it would also add some false positives, such as "1.2--3", but so it already did with "1.2 3" (spaces inside the number) - maybe one line from my proposal could be added so that it properly checks non-ZERO_VECTORs, at least. -- Shuichi Shinji 08:30, 4 April 2014 (PDT)

<lsl> integer IsVector(string s) {

   list split = llParseString2List(s, [" ", "-"], ["<", ">", ","]);
   if(llGetListLength(split) != 7)//we must check the list length, or the next test won't work properly.
       return FALSE;
   if((vector)s != ZERO_VECTOR)//parsing error or real ZERO_VECTOR lead to ZERO_VECTOR
       return TRUE;
   return !((string)((vector)s) == (string)((vector)((string)llListInsertList(split, ["-"], 5))));
   //it works by trying to flip the sign on the Z element of the vector,
   //if it works or breaks the vector then the values won't match.
   //if the vector was already broken then the sign flip will have no affect and the values will match
   //we cast back to string so we can catch negative zero which allows for support of ZERO_VECTOR

} </lsl>


Correction

Ok, your function does work for negative z's, I must have made a mistake when I first checked it - sorry for the confusion. However, I have a few improvements:

  • don't filter out spaces during the split, because e.g. " < 1 , 2 , 3 > " is not a valid vector (the leading spaces are the problem): <lsl>list split = llParseString2List( s, [], ["<", ">", ","] );</lsl>
  • for rotations, don't add the "-" for the s member, but for z (I had problems with s)

With these, the following checks all work (in SL; LSLeditor interprets it a bit differently in some cases):

<lsl> llOwnerSay( "IsVector(<0.47,0.149, 1.001>) -> 1: " + (string)IsVector( "<0.47,0.149, 1.001>" ) ); llOwnerSay( "IsVector(<0.47,0.149, 1.001,3>) -> 0: " + (string)IsVector( "<0.47,0.149, 1.001,3>" ) ); llOwnerSay( "IsVector(<0.47,0.149,-1.001>) -> 1: " + (string)IsVector( "<0.47,0.149,-1.001>" ) ); llOwnerSay( "IsVector(<0.47,0.149,+1.001>) -> 1: " + (string)IsVector( "<0.47,0.149,+1.001>" ) ); llOwnerSay( "IsVector(< 0.47, 0.149, -1.001 >) -> 1: " + (string)IsVector( "< 0.47, 0.149, -1.001 >" ) ); llOwnerSay( "IsVector( < 0.47, 0.149, -1.001 > ) -> 0: " + (string)IsVector( " < 0.47, 0.149, -1.001 > " ) ); llOwnerSay( "IsVector(<0.47,0.1A9,-1.001>) -> 0: " + (string)IsVector( "<0.47,0.1A9,-1.001>" ) ); llOwnerSay( "IsVector(<0.47,0.149,;-1.001>) -> 0: " + (string)IsVector( "<0.47,;0.149,-1.001>" ) ); llOwnerSay( "IsVector(<0.47,0.149,-1.001) -> 0: " + (string)IsVector( "<0.47,0.149,-1.001" ) ); llOwnerSay( "IsVector(<0,0.000,0>) -> 1: " + (string)IsVector( "<0,0.000,0>" ) ); llOwnerSay( "IsVector(<0,0.000,0,0>) -> 0: " + (string)IsVector( "<0,0.000,0,0>" ) ); llOwnerSay( "IsVector(<+0,-0.000,-0>) -> 1: " + (string)IsVector( "<+0,-0.000,-0>" ) ); llOwnerSay( "IsVector(<0x0.0,0x0p+1,-0x0p-1>) -> 1: " + (string)IsVector( "<0x0.0,0x0.p+1,-0x0.p-1>" ) ); llOwnerSay( "IsVector(<0.0e1,0.0e+1,-0.0e-1>) -> 1: " + (string)IsVector( "<0.0e1,0.0e+1,-0.0e-1>" ) ); llOwnerSay( "IsRotation(<0.47,0.149,-1.001>) -> 0: " + (string)IsRotation( "<0.47,0.149,-1.001>" ) ); llOwnerSay( "IsRotation(<0.47,0.149,-1.001,3>) -> 1: " + (string)IsRotation( "<0.47,0.149,-1.001,3>" ) ); llOwnerSay( "IsRotation(<0.47,0.149,+1.001,3>) -> 1: " + (string)IsRotation( "<0.47,0.149,+1.001,3>" ) ); llOwnerSay( "IsRotation(< 0.47, 0.149, 0.99,3 >) -> 1: " + (string)IsRotation( "< 0.47, 0.149, 0.99,3 >" ) ); llOwnerSay( "IsRotation( < 0.47, 0.149, 0.99,3 > ) -> 0: " + (string)IsRotation( " < 0.47, 0.149, 0.99,3 > " ) ); llOwnerSay( "IsRotation(<0.47,0.1A9,-1.001,3>) -> 0: " + (string)IsRotation( "<0.47,0.1A9,-1.001,3>" ) ); llOwnerSay( "IsRotation(<0.47,0.149,-1.001,;3>) -> 0: " + (string)IsRotation( "<0.47,;0.149,-1.001,3>" ) ); llOwnerSay( "IsRotation(<0.47,0.149,-1.001,3) -> 0: " + (string)IsRotation( "<0.47,0.149,-1.001,3" ) ); llOwnerSay( "IsRotation(<0,0.000,0>) -> 0: " + (string)IsRotation( "<0,0.000,0>" ) ); llOwnerSay( "IsRotation(<0,0.000,0,0>) -> 1: " + (string)IsRotation( "<0,0.000,0,0>" ) ); llOwnerSay( "IsRotation(<+0,-0.000,-0,-0>) -> 1: " + (string)IsRotation( "<+0,-0.000,-0,-0>" ) ); </lsl>

Not relevant for SL, just a remark: For grids where the "-" approach does not work because negative zeros are filtered out during the casts, the following slightly less elegant works instead:

<lsl> // vector if ( (vector)((string)llListReplaceList( split, [1], 5, 5 )) == ZERO_VECTOR ) return FALSE; // parsing error in x or y return ((vector)((string)llListReplaceList( split, [1], 3, 3 )) != ZERO_VECTOR); // parsing error in z // rotation if ( (rotation)((string)llListReplaceList( split, [2], 7, 7 )) == ZERO_ROTATION ) return FALSE; // parsing error in x, y or z return ((rotation)((string)llListReplaceList( split, [1], 5, 5 )) != ZERO_ROTATION); // parsing error in s </lsl>

Shuichi Shinji 01:20, 10 April 2014 (PDT)