From 39503419163aff0cb1cd305de924f4edc68833b0 Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Thu, 29 Apr 2021 17:37:26 +0300
Subject: SL-15177 Added LLTextureFetchTester to log texture fetching state
 timers

---
 indra/llcommon/llmetricperformancetester.cpp | 1 -
 1 file changed, 1 deletion(-)

(limited to 'indra/llcommon')

diff --git a/indra/llcommon/llmetricperformancetester.cpp b/indra/llcommon/llmetricperformancetester.cpp
index f8a93baf45..100eb57555 100644
--- a/indra/llcommon/llmetricperformancetester.cpp
+++ b/indra/llcommon/llmetricperformancetester.cpp
@@ -189,7 +189,6 @@ LLMetricPerformanceTesterBasic::~LLMetricPerformanceTesterBasic()
 void LLMetricPerformanceTesterBasic::preOutputTestResults(LLSD* sd) 
 {
 	incrementCurrentCount() ;
-	(*sd)[getCurrentLabelName()]["Name"] = mName ;
 }
 
 void LLMetricPerformanceTesterBasic::postOutputTestResults(LLSD* sd)
-- 
cgit v1.2.3


From ab3261f901d34fab154c63edd3248c6231dc0798 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 14 Sep 2021 18:30:57 +0300
Subject: SL-15997 Windows 11 version detection

---
 indra/llcommon/llsys.cpp | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

(limited to 'indra/llcommon')

diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp
index 4e61fb8a58..94f669b0f9 100644
--- a/indra/llcommon/llsys.cpp
+++ b/indra/llcommon/llsys.cpp
@@ -140,7 +140,13 @@ LLOSInfo::LLOSInfo() :
 
 #if LL_WINDOWS
 
-	if (IsWindowsVersionOrGreater(10, 0, 0))
+    if (IsWindowsVersionOrGreater(11, 0, 0))
+    {
+        mMajorVer = 11;
+        mMinorVer = 0;
+        mOSStringSimple = "Microsoft Windows 11 ";
+    }
+    else if (IsWindows10OrGreater())
 	{
 		mMajorVer = 10;
 		mMinorVer = 0;
-- 
cgit v1.2.3


From 96d7cd29f636fa570498b7fa4b71eabc4e1923eb Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Wed, 15 Sep 2021 22:31:02 +0300
Subject: SL-16004 Fix bugsplat displaying wrong top function

bugsplat shows KERNELBASE!RaiseException and flush() insread of forceErrorLLError, function crashes too early.
---
 indra/llcommon/llerror.cpp | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

(limited to 'indra/llcommon')

diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index 8355df9045..b45411ad9d 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -1397,7 +1397,10 @@ namespace LLError
 		if (site.mLevel == LEVEL_ERROR)
 		{
 			g->mFatalMessage = message;
-			s->mCrashFunction(message);
+            if (s->mCrashFunction)
+            {
+                s->mCrashFunction(message);
+            }
 		}
 	}
 }
-- 
cgit v1.2.3


From 4be6981c6d8eefb28383358b7a0beaeca8100a0d Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 19 Oct 2021 00:41:19 +0300
Subject: SL-15964 Fix gzip failing to compress files into unicode paths

---
 indra/llcommon/llsys.cpp | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

(limited to 'indra/llcommon')

diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp
index 94f669b0f9..e94973ac29 100644
--- a/indra/llcommon/llsys.cpp
+++ b/indra/llcommon/llsys.cpp
@@ -1261,7 +1261,12 @@ BOOL gunzip_file(const std::string& srcfile, const std::string& dstfile)
 	LLFILE *dst = NULL;
 	S32 bytes = 0;
 	tmpfile = dstfile + ".t";
-	src = gzopen(srcfile.c_str(), "rb");
+#ifdef LL_WINDOWS
+    llutf16string utf16filename = utf8str_to_utf16str(srcfile);
+    src = gzopen_w(utf16filename.c_str(), "rb");
+#else
+    src = gzopen(srcfile.c_str(), "rb");
+#endif
 	if (! src) goto err;
 	dst = LLFile::fopen(tmpfile, "wb");		/* Flawfinder: ignore */
 	if (! dst) goto err;
@@ -1295,7 +1300,14 @@ BOOL gzip_file(const std::string& srcfile, const std::string& dstfile)
 	LLFILE *src = NULL;
 	S32 bytes = 0;
 	tmpfile = dstfile + ".t";
-	dst = gzopen(tmpfile.c_str(), "wb");		/* Flawfinder: ignore */
+
+#ifdef LL_WINDOWS
+    llutf16string utf16filename = utf8str_to_utf16str(tmpfile);
+    dst = gzopen_w(utf16filename.c_str(), "wb");
+#else
+    dst = gzopen(tmpfile.c_str(), "wb");
+#endif
+
 	if (! dst) goto err;
 	src = LLFile::fopen(srcfile, "rb");		/* Flawfinder: ignore */
 	if (! src) goto err;
-- 
cgit v1.2.3


From 1b5d151c156f0528e58c02b494d4b515ea9cb11c Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Wed, 20 Oct 2021 23:57:48 +0300
Subject: SL-15997 Windows 11 detection

---
 indra/llcommon/llsys.cpp | 23 ++++++++++++++++-------
 1 file changed, 16 insertions(+), 7 deletions(-)

(limited to 'indra/llcommon')

diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp
index e94973ac29..4fe5b6bf20 100644
--- a/indra/llcommon/llsys.cpp
+++ b/indra/llcommon/llsys.cpp
@@ -140,13 +140,7 @@ LLOSInfo::LLOSInfo() :
 
 #if LL_WINDOWS
 
-    if (IsWindowsVersionOrGreater(11, 0, 0))
-    {
-        mMajorVer = 11;
-        mMinorVer = 0;
-        mOSStringSimple = "Microsoft Windows 11 ";
-    }
-    else if (IsWindows10OrGreater())
+    if (IsWindows10OrGreater())
 	{
 		mMajorVer = 10;
 		mMinorVer = 0;
@@ -279,6 +273,21 @@ LLOSInfo::LLOSInfo() :
 				ubr = data;
 			}
 		}
+
+        if (mBuild >= 22000)
+        {
+            // At release Windows 11 version was 10.0.22000.194
+            // Windows 10 version was 10.0.19043.1266
+            // There is no warranty that Win10 build won't increase,
+            // so until better solution is found or Microsoft updates
+            // SDK with IsWindows11OrGreater(), indicate "10/11"
+            //
+            // Current alternatives:
+            // Query WMI's Win32_OperatingSystem for OS string. Slow
+            // and likely to return 'compatibility' string.
+            // Check presence of dlls/libs or may be their version.
+            mOSStringSimple = "Microsoft Windows 10/11";
+        }
 	}
 
 	mOSString = mOSStringSimple;
-- 
cgit v1.2.3


From 7f0fcfa33240bf54371fb689cc61ee83e6991150 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Wed, 17 Nov 2021 23:27:17 +0200
Subject: SL-15241 Cleanup

---
 indra/llcommon/llerror.cpp | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

(limited to 'indra/llcommon')

diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index f0aacfa1be..2fe2e1bbce 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -498,8 +498,6 @@ namespace
     protected:
 		Globals();
 	public:
-		std::ostringstream messageStream;
-		bool messageStreamInUse;
 		std::string mFatalMessage;
 
 		void addCallSite(LLError::CallSite&);
@@ -516,8 +514,7 @@ namespace
 	};
 
 	Globals::Globals()
-		: messageStream(),
-		messageStreamInUse(false),
+		:
 		callSites(),
         mSettingsConfig(new SettingsConfig())
 	{
-- 
cgit v1.2.3


From f729cfc33f258781c5fd85a3d8773bf6149d12db Mon Sep 17 00:00:00 2001
From: Bennett Goble <signal@lindenlab.com>
Date: Sat, 5 Jun 2021 22:02:54 -0700
Subject: SL-15742: Convert build scripts to Python 3

This changeset makes it possible to build the Second Life viewer using
Python 3. It is designed to be used with an equivalent Autobuild branch
so that a developer can compile without needing Python 2 on their
machine.

Breaking change: Python 2 support ending

Rather than supporting two versions of Python, including one that was
discontinued at the beginning of the year, this branch focuses on
pouring future effort into Python 3 only. As a result, scripts do not
need to be backwards compatible. This means that build environments,
be they on personal computers and on build agents, need to have a
compatible interpreter.

Notes

- SLVersionChecker will still use Python 2 on macOS
- Fixed the message template url used by template_verifier.py
---
 indra/llcommon/llleap.cpp                   |  2 +-
 indra/llcommon/tests/llleap_test.cpp        | 41 +++++++++++++++--------------
 indra/llcommon/tests/llprocess_test.cpp     | 30 ++++++++++++---------
 indra/llcommon/tests/llsdserialize_test.cpp | 15 +++++------
 4 files changed, 46 insertions(+), 42 deletions(-)

(limited to 'indra/llcommon')

diff --git a/indra/llcommon/llleap.cpp b/indra/llcommon/llleap.cpp
index e8ea0ab398..2704f8b6de 100644
--- a/indra/llcommon/llleap.cpp
+++ b/indra/llcommon/llleap.cpp
@@ -86,7 +86,7 @@ public:
             // notice Python specially: we provide Python LLSD serialization
             // support, so there's a pretty good reason to implement plugins
             // in that language.
-            if (cparams.args.size() && (desclower == "python" || desclower == "python.exe"))
+            if (cparams.args.size() && (desclower == "python" || desclower == "python3" || desclower == "python.exe"))
             {
                 mDesc = LLProcess::basename(cparams.args()[0]);
             }
diff --git a/indra/llcommon/tests/llleap_test.cpp b/indra/llcommon/tests/llleap_test.cpp
index 9d71e327d8..9754353ab0 100644
--- a/indra/llcommon/tests/llleap_test.cpp
+++ b/indra/llcommon/tests/llleap_test.cpp
@@ -145,13 +145,13 @@ namespace tut
                    "    data = ''.join(parts)\n"
                    "    assert len(data) == length\n"
                    "    try:\n"
-                   "        return llsd.parse(data)\n"
+                   "        return llsd.parse(data.encode())\n"
                    //   Seems the old indra.base.llsd module didn't properly
                    //   convert IndexError (from running off end of string) to
                    //   LLSDParseError.
-                   "    except (IndexError, llsd.LLSDParseError), e:\n"
+                   "    except (IndexError, llsd.LLSDParseError) as e:\n"
                    "        msg = 'Bad received packet (%s)' % e\n"
-                   "        print >>sys.stderr, '%s, %s bytes:' % (msg, len(data))\n"
+                   "        print('%s, %s bytes:' % (msg, len(data)), file=sys.stderr)\n"
                    "        showmax = 40\n"
                    //       We've observed failures with very large packets;
                    //       dumping the entire packet wastes time and space.
@@ -167,12 +167,12 @@ namespace tut
                    "            data = data[:trunc]\n"
                    "            ellipsis = '... (%s more)' % (length - trunc)\n"
                    "        offset = -showmax\n"
-                   "        for offset in xrange(0, len(data)-showmax, showmax):\n"
-                   "            print >>sys.stderr, '%04d: %r +' % \\\n"
-                   "                  (offset, data[offset:offset+showmax])\n"
+                   "        for offset in range(0, len(data)-showmax, showmax):\n"
+                   "            print('%04d: %r +' % \\\n"
+                   "                  (offset, data[offset:offset+showmax]), file=sys.stderr)\n"
                    "        offset += showmax\n"
-                   "        print >>sys.stderr, '%04d: %r%s' % \\\n"
-                   "              (offset, data[offset:], ellipsis)\n"
+                   "        print('%04d: %r%s' % \\\n"
+                   "              (offset, data[offset:], ellipsis), file=sys.stderr)\n"
                    "        raise ParseError(msg, data)\n"
                    "\n"
                    "# deal with initial stdin message\n"
@@ -189,7 +189,7 @@ namespace tut
                    "    sys.stdout.flush()\n"
                    "\n"
                    "def send(pump, data):\n"
-                   "    put(llsd.format_notation(dict(pump=pump, data=data)))\n"
+                   "    put(llsd.format_notation(dict(pump=pump, data=data)).decode())\n"
                    "\n"
                    "def request(pump, data):\n"
                    "    # we expect 'data' is a dict\n"
@@ -253,7 +253,7 @@ namespace tut
     {
         set_test_name("bad stdout protocol");
         NamedTempFile script("py",
-                             "print 'Hello from Python!'\n");
+                             "print('Hello from Python!')\n");
         CaptureLog log(LLError::LEVEL_WARN);
         waitfor(LLLeap::create(get_test_name(),
                                sv(list_of(PYTHON)(script.getName()))));
@@ -438,8 +438,8 @@ namespace tut
                              // guess how many messages it will take to
                              // accumulate BUFFERED_LENGTH
                              "count = int(" << BUFFERED_LENGTH << "/samplen)\n"
-                             "print >>sys.stderr, 'Sending %s requests' % count\n"
-                             "for i in xrange(count):\n"
+                             "print('Sending %s requests' % count, file=sys.stderr)\n"
+                             "for i in range(count):\n"
                              "    request('" << api.getName() << "', dict(reqid=i))\n"
                              // The assumption in this specific test that
                              // replies will arrive in the same order as
@@ -450,7 +450,7 @@ namespace tut
                              // arbitrary order, and we'd have to tick them
                              // off from a set.
                              "result = ''\n"
-                             "for i in xrange(count):\n"
+                             "for i in range(count):\n"
                              "    resp = get()\n"
                              "    if resp['data']['reqid'] != i:\n"
                              "        result = 'expected reqid=%s in %s' % (i, resp)\n"
@@ -476,13 +476,13 @@ namespace tut
                              "desired = int(sys.argv[1])\n"
                              // 7 chars per item: 6 digits, 1 comma
                              "count = int((desired - 50)/7)\n"
-                             "large = ''.join('%06d,' % i for i in xrange(count))\n"
+                             "large = ''.join('%06d,' % i for i in range(count))\n"
                              // Pass 'large' as reqid because we know the API
                              // will echo reqid, and we want to receive it back.
                              "request('" << api.getName() << "', dict(reqid=large))\n"
                              "try:\n"
                              "    resp = get()\n"
-                             "except ParseError, e:\n"
+                             "except ParseError as e:\n"
                              "    # try to find where e.data diverges from expectation\n"
                              // Normally we'd expect a 'pump' key in there,
                              // too, with value replypump(). But Python
@@ -493,17 +493,18 @@ namespace tut
                              // strange.
                              "    expect = llsd.format_notation(dict(data=dict(reqid=large)))\n"
                              "    chunk = 40\n"
-                             "    for offset in xrange(0, max(len(e.data), len(expect)), chunk):\n"
+                             "    for offset in range(0, max(len(e.data), len(expect)), chunk):\n"
                              "        if e.data[offset:offset+chunk] != \\\n"
                              "           expect[offset:offset+chunk]:\n"
-                             "            print >>sys.stderr, 'Offset %06d: expect %r,\\n'\\\n"
+                             "            print('Offset %06d: expect %r,\\n'\\\n"
                              "                                '                  get %r' %\\\n"
                              "                                (offset,\n"
                              "                                 expect[offset:offset+chunk],\n"
-                             "                                 e.data[offset:offset+chunk])\n"
+                             "                                 e.data[offset:offset+chunk]),\n"
+                             "                                 file=sys.stderr)\n"
                              "            break\n"
                              "    else:\n"
-                             "        print >>sys.stderr, 'incoming data matches expect?!'\n"
+                             "        print('incoming data matches expect?!', file=sys.stderr)\n"
                              "    send('" << result.getName() << "', '%s: %s' % (e.__class__.__name__, e))\n"
                              "    sys.exit(1)\n"
                              "\n"
@@ -512,7 +513,7 @@ namespace tut
                              "    send('" << result.getName() << "', '')\n"
                              "    sys.exit(0)\n"
                              // Here we know echoed did NOT match; try to find where
-                             "for i in xrange(count):\n"
+                             "for i in range(count):\n"
                              "    start = 7*i\n"
                              "    end   = 7*(i+1)\n"
                              "    if end > len(echoed)\\\n"
diff --git a/indra/llcommon/tests/llprocess_test.cpp b/indra/llcommon/tests/llprocess_test.cpp
index f0eafa8201..e530975e86 100644
--- a/indra/llcommon/tests/llprocess_test.cpp
+++ b/indra/llcommon/tests/llprocess_test.cpp
@@ -360,10 +360,10 @@ namespace tut
             "import time" EOL
             EOL
             "time.sleep(2)" EOL
-            "print >>sys.stdout, 'stdout after wait'" EOL
+            "print('stdout after wait', file=sys.stdout)" EOL
             "sys.stdout.flush()" EOL
             "time.sleep(2)" EOL
-            "print >>sys.stderr, 'stderr after wait'" EOL
+            "print('stderr after wait', file=sys.stderr)" EOL
             "sys.stderr.flush()" EOL
             );
 
@@ -381,7 +381,11 @@ namespace tut
 
         std::vector<const char*> argv;
         apr_proc_t child;
+#if defined(LL_WINDOWS)
         argv.push_back("python");
+#else
+        argv.push_back("python3");
+#endif
         // Have to have a named copy of this std::string so its c_str() value
         // will persist.
         std::string scriptname(script.getName());
@@ -573,7 +577,7 @@ namespace tut
                                  // note nonstandard output-file arg!
                                  "with open(sys.argv[3], 'w') as f:\n"
                                  "    for arg in sys.argv[1:]:\n"
-                                 "        print >>f, arg\n");
+                                 "        print(arg, file=f)\n");
         // We expect that PythonProcessLauncher has already appended
         // its own NamedTempFile to mParams.args (sys.argv[0]).
         py.mParams.args.add("first arg");          // sys.argv[1]
@@ -742,7 +746,7 @@ namespace tut
                                      "with open(sys.argv[1], 'w') as f:\n"
                                      "    f.write('ok')\n"
                                      "# wait for 'go' from test program\n"
-                                     "for i in xrange(60):\n"
+                                     "for i in range(60):\n"
                                      "    time.sleep(1)\n"
                                      "    with open(sys.argv[2]) as f:\n"
                                      "        go = f.read()\n"
@@ -804,7 +808,7 @@ namespace tut
                                      "with open(sys.argv[1], 'w') as f:\n"
                                      "    f.write('ok')\n"
                                      "# wait for 'go' from test program\n"
-                                     "for i in xrange(60):\n"
+                                     "for i in range(60):\n"
                                      "    time.sleep(1)\n"
                                      "    with open(sys.argv[2]) as f:\n"
                                      "        go = f.read()\n"
@@ -857,7 +861,7 @@ namespace tut
         set_test_name("'bogus' test");
         CaptureLog recorder;
         PythonProcessLauncher py(get_test_name(),
-                                 "print 'Hello world'\n");
+                                 "print('Hello world')\n");
         py.mParams.files.add(LLProcess::FileParam("bogus"));
         py.mPy = LLProcess::create(py.mParams);
         ensure("should have rejected 'bogus'", ! py.mPy);
@@ -872,7 +876,7 @@ namespace tut
         // Replace this test with one or more real 'file' tests when we
         // implement 'file' support
         PythonProcessLauncher py(get_test_name(),
-                                 "print 'Hello world'\n");
+                                 "print('Hello world')\n");
         py.mParams.files.add(LLProcess::FileParam());
         py.mParams.files.add(LLProcess::FileParam("file"));
         py.mPy = LLProcess::create(py.mParams);
@@ -887,7 +891,7 @@ namespace tut
         // implement 'tpipe' support
         CaptureLog recorder;
         PythonProcessLauncher py(get_test_name(),
-                                 "print 'Hello world'\n");
+                                 "print('Hello world')\n");
         py.mParams.files.add(LLProcess::FileParam());
         py.mParams.files.add(LLProcess::FileParam("tpipe"));
         py.mPy = LLProcess::create(py.mParams);
@@ -904,7 +908,7 @@ namespace tut
         // implement 'npipe' support
         CaptureLog recorder;
         PythonProcessLauncher py(get_test_name(),
-                                 "print 'Hello world'\n");
+                                 "print('Hello world')\n");
         py.mParams.files.add(LLProcess::FileParam());
         py.mParams.files.add(LLProcess::FileParam());
         py.mParams.files.add(LLProcess::FileParam("npipe"));
@@ -980,7 +984,7 @@ namespace tut
     {
         set_test_name("get*Pipe() validation");
         PythonProcessLauncher py(get_test_name(),
-                                 "print 'this output is expected'\n");
+                                 "print('this output is expected)'\n");
         py.mParams.files.add(LLProcess::FileParam("pipe")); // pipe for  stdin
         py.mParams.files.add(LLProcess::FileParam());       // inherit stdout
         py.mParams.files.add(LLProcess::FileParam("pipe")); // pipe for stderr
@@ -1001,13 +1005,13 @@ namespace tut
         set_test_name("talk to stdin/stdout");
         PythonProcessLauncher py(get_test_name(),
                                  "import sys, time\n"
-                                 "print 'ok'\n"
+                                 "print('ok')\n"
                                  "sys.stdout.flush()\n"
                                  "# wait for 'go' from test program\n"
                                  "go = sys.stdin.readline()\n"
                                  "if go != 'go\\n':\n"
                                  "    sys.exit('expected \"go\", saw %r' % go)\n"
-                                 "print 'ack'\n");
+                                 "print('ack')\n");
         py.mParams.files.add(LLProcess::FileParam("pipe")); // stdin
         py.mParams.files.add(LLProcess::FileParam("pipe")); // stdout
         py.launch();
@@ -1118,7 +1122,7 @@ namespace tut
     {
         set_test_name("ReadPipe \"eof\" event");
         PythonProcessLauncher py(get_test_name(),
-                                 "print 'Hello from Python!'\n");
+                                 "print('Hello from Python!')\n");
         py.mParams.files.add(LLProcess::FileParam()); // stdin
         py.mParams.files.add(LLProcess::FileParam("pipe")); // stdout
         py.launch();
diff --git a/indra/llcommon/tests/llsdserialize_test.cpp b/indra/llcommon/tests/llsdserialize_test.cpp
index 642c1c3879..c246f5ee56 100644
--- a/indra/llcommon/tests/llsdserialize_test.cpp
+++ b/indra/llcommon/tests/llsdserialize_test.cpp
@@ -1795,7 +1795,7 @@ namespace tut
         set_test_name("verify NamedTempFile");
         python("platform",
                "import sys\n"
-               "print 'Running on', sys.platform\n");
+               "print('Running on', sys.platform)\n");
     }
 
     // helper for test<3>
@@ -1825,14 +1825,14 @@ namespace tut
         const char pydata[] =
             "def verify(iterable):\n"
             "    it = iter(iterable)\n"
-            "    assert it.next() == 17\n"
-            "    assert abs(it.next() - 3.14) < 0.01\n"
-            "    assert it.next() == '''\\\n"
+            "    assert next(it) == 17\n"
+            "    assert abs(next(it) - 3.14) < 0.01\n"
+            "    assert next(it) == '''\\\n"
             "This string\n"
             "has several\n"
             "lines.'''\n"
             "    try:\n"
-            "        it.next()\n"
+            "        next(it)\n"
             "    except StopIteration:\n"
             "        pass\n"
             "    else:\n"
@@ -1855,7 +1855,7 @@ namespace tut
                "        yield llsd.parse(item)\n" <<
                pydata <<
                // Don't forget raw-string syntax for Windows pathnames.
-               "verify(parse_each(open(r'" << file.getName() << "')))\n");
+               "verify(parse_each(open(r'" << file.getName() << "', 'rb')))\n");
     }
 
     template<> template<>
@@ -1870,7 +1870,6 @@ namespace tut
 
         python("write Python notation",
                placeholders::arg1 <<
-               "from __future__ import with_statement\n" <<
                import_llsd <<
                "DATA = [\n"
                "    17,\n"
@@ -1884,7 +1883,7 @@ namespace tut
                // N.B. Using 'print' implicitly adds newlines.
                "with open(r'" << file.getName() << "', 'w') as f:\n"
                "    for item in DATA:\n"
-               "        print >>f, llsd.format_notation(item)\n");
+               "        print(llsd.format_notation(item).decode(), file=f)\n");
 
         std::ifstream inf(file.getName().c_str());
         LLSD item;
-- 
cgit v1.2.3