Home | History | Annotate | Download | only in accessibility
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <string>
      6 
      7 #include "ash/magnifier/magnification_controller.h"
      8 #include "ash/shell.h"
      9 #include "base/command_line.h"
     10 #include "base/prefs/pref_service.h"
     11 #include "chrome/browser/browser_process.h"
     12 #include "chrome/browser/chrome_notification_types.h"
     13 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
     14 #include "chrome/browser/chromeos/accessibility/magnification_manager.h"
     15 #include "chrome/browser/chromeos/cros/cros_in_process_browser_test.h"
     16 #include "chrome/browser/chromeos/login/helper.h"
     17 #include "chrome/browser/chromeos/login/login_utils.h"
     18 #include "chrome/browser/chromeos/login/user_manager.h"
     19 #include "chrome/browser/chromeos/login/user_manager_impl.h"
     20 #include "chrome/browser/profiles/profile.h"
     21 #include "chrome/browser/profiles/profile_manager.h"
     22 #include "chrome/common/chrome_switches.h"
     23 #include "chrome/common/pref_names.h"
     24 #include "chrome/test/base/testing_profile.h"
     25 #include "chromeos/chromeos_switches.h"
     26 #include "components/user_prefs/user_prefs.h"
     27 #include "content/public/browser/notification_details.h"
     28 #include "content/public/browser/notification_service.h"
     29 #include "testing/gtest/include/gtest/gtest.h"
     30 
     31 namespace chromeos {
     32 
     33 namespace {
     34 
     35 const char kTestUserName[] = "owner (at) invalid.domain";
     36 
     37 void SetMagnifierEnabled(bool enabled) {
     38   MagnificationManager::Get()->SetMagnifierEnabled(enabled);
     39 }
     40 
     41 void SetMagnifierType(ash::MagnifierType type) {
     42   MagnificationManager::Get()->SetMagnifierType(type);
     43 }
     44 
     45 void SetFullScreenMagnifierScale(double scale) {
     46   ash::Shell::GetInstance()->
     47       magnification_controller()->SetScale(scale, false);
     48 }
     49 
     50 double GetFullScreenMagnifierScale() {
     51   return ash::Shell::GetInstance()->magnification_controller()->GetScale();
     52 }
     53 
     54 void SetSavedFullScreenMagnifierScale(double scale) {
     55   MagnificationManager::Get()->SaveScreenMagnifierScale(scale);
     56 }
     57 
     58 double GetSavedFullScreenMagnifierScale() {
     59   return MagnificationManager::Get()->GetSavedScreenMagnifierScale();
     60 }
     61 
     62 ash::MagnifierType GetMagnifierType() {
     63   return MagnificationManager::Get()->GetMagnifierType();
     64 }
     65 
     66 bool IsMagnifierEnabled() {
     67   return MagnificationManager::Get()->IsMagnifierEnabled();
     68 }
     69 
     70 Profile* profile() {
     71   Profile* profile = ProfileManager::GetDefaultProfileOrOffTheRecord();
     72   DCHECK(profile);
     73   return profile;
     74 }
     75 
     76 PrefService* prefs() {
     77   return user_prefs::UserPrefs::Get(profile());
     78 }
     79 
     80 void SetScreenMagnifierEnabledPref(bool enabled) {
     81   prefs()->SetBoolean(prefs::kScreenMagnifierEnabled, enabled);
     82 }
     83 
     84 void SetScreenMagnifierTypePref(ash::MagnifierType type) {
     85   prefs()->SetInteger(prefs::kScreenMagnifierType, type);
     86 }
     87 
     88 void SetFullScreenMagnifierScalePref(double scale) {
     89   prefs()->SetDouble(prefs::kScreenMagnifierScale, scale);
     90 }
     91 
     92 bool GetScreenMagnifierEnabledFromPref() {
     93   return prefs()->GetBoolean(prefs::kScreenMagnifierEnabled);
     94 }
     95 
     96 // Creates and logs into a profile with account |name|, and makes sure that
     97 // the profile is regarded as "non new" in the next login. This is used in
     98 // PRE_XXX cases so that in the main XXX case we can test non new profiles.
     99 void PrepareNonNewProfile(const std::string& name) {
    100   UserManager::Get()->UserLoggedIn(name, name, true);
    101   // To prepare a non-new profile for tests, we must ensure the profile
    102   // directory and the preference files are created, because that's what
    103   // Profile::IsNewProfile() checks. UserLoggedIn(), however, does not yet
    104   // create the profile directory until GetDefaultProfile() is called.
    105   ProfileManager::GetDefaultProfile();
    106 }
    107 
    108 }  // namespace
    109 
    110 class MagnificationManagerTest : public CrosInProcessBrowserTest,
    111                                  public content::NotificationObserver {
    112  protected:
    113   MagnificationManagerTest() : observed_(false),
    114                                observed_enabled_(false),
    115                                observed_type_(ash::kDefaultMagnifierType) {}
    116   virtual ~MagnificationManagerTest() {}
    117 
    118   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    119     command_line->AppendSwitch(switches::kLoginManager);
    120     command_line->AppendSwitchASCII(switches::kLoginProfile,
    121                                     TestingProfile::kTestUserProfileDir);
    122   }
    123 
    124   virtual void SetUpOnMainThread() OVERRIDE {
    125     registrar_.Add(
    126         this,
    127         chrome::NOTIFICATION_CROS_ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFIER,
    128         content::NotificationService::AllSources());
    129 
    130     // Set the login-screen profile.
    131     MagnificationManager::Get()->SetProfileForTest(
    132         ProfileManager::GetDefaultProfile());
    133   }
    134 
    135   // content::NotificationObserver implementation.
    136   virtual void Observe(int type,
    137                        const content::NotificationSource& source,
    138                        const content::NotificationDetails& details) OVERRIDE {
    139     switch (type) {
    140       case chrome::NOTIFICATION_CROS_ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFIER: {
    141         AccessibilityStatusEventDetails* accessibility_status =
    142             content::Details<AccessibilityStatusEventDetails>(details).ptr();
    143 
    144         observed_ = true;
    145         observed_enabled_ = accessibility_status->enabled;
    146         observed_type_ = accessibility_status->magnifier_type;
    147         break;
    148       }
    149     }
    150   }
    151 
    152   bool observed_;
    153   bool observed_enabled_;
    154   ash::MagnifierType observed_type_;
    155   content::NotificationRegistrar registrar_;
    156   DISALLOW_COPY_AND_ASSIGN(MagnificationManagerTest);
    157 };
    158 
    159 IN_PROC_BROWSER_TEST_F(MagnificationManagerTest, PRE_LoginOffToOff) {
    160   // Create a new profile once, to run the test with non-new profile.
    161   PrepareNonNewProfile(kTestUserName);
    162 
    163   // Sets pref to explicitly disable the magnifier.
    164   SetScreenMagnifierEnabledPref(false);
    165 }
    166 
    167 IN_PROC_BROWSER_TEST_F(MagnificationManagerTest, LoginOffToOff) {
    168   // Confirms that magnifier is disabled on the login screen.
    169   EXPECT_FALSE(IsMagnifierEnabled());
    170 
    171   // Disables magnifier on login screen.
    172   SetMagnifierEnabled(false);
    173   EXPECT_FALSE(IsMagnifierEnabled());
    174 
    175   // Logs in with existing profile.
    176   UserManager::Get()->UserLoggedIn(kTestUserName, kTestUserName, true);
    177 
    178   // Confirms that magnifier is still disabled just after login.
    179   EXPECT_FALSE(IsMagnifierEnabled());
    180 
    181   UserManager::Get()->SessionStarted();
    182 
    183   // Confirms that magnifier is still disabled just after session starts.
    184   EXPECT_FALSE(IsMagnifierEnabled());
    185 
    186   // Enables magnifier.
    187   SetMagnifierEnabled(true);
    188   // Confirms that magnifier is enabled.
    189   EXPECT_TRUE(IsMagnifierEnabled());
    190   EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
    191   EXPECT_TRUE(GetScreenMagnifierEnabledFromPref());
    192 }
    193 
    194 IN_PROC_BROWSER_TEST_F(MagnificationManagerTest, PRE_LoginFullToOff) {
    195   // Create a new profile once, to run the test with non-new profile.
    196   PrepareNonNewProfile(kTestUserName);
    197 
    198   // Sets pref to explicitly disable the magnifier.
    199   SetScreenMagnifierEnabledPref(false);
    200 }
    201 
    202 IN_PROC_BROWSER_TEST_F(MagnificationManagerTest, LoginFullToOff) {
    203   // Confirms that magnifier is disabled on the login screen.
    204   EXPECT_FALSE(IsMagnifierEnabled());
    205 
    206   // Enables magnifier on login screen.
    207   SetMagnifierEnabled(true);
    208   SetMagnifierType(ash::MAGNIFIER_FULL);
    209   SetFullScreenMagnifierScale(2.5);
    210   EXPECT_TRUE(IsMagnifierEnabled());
    211   EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
    212   EXPECT_EQ(2.5, GetFullScreenMagnifierScale());
    213 
    214   // Logs in (but the session is not started yet).
    215   UserManager::Get()->UserLoggedIn(kTestUserName, kTestUserName, true);
    216 
    217   // Confirms that magnifier is keeping enabled.
    218   EXPECT_TRUE(IsMagnifierEnabled());
    219   EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
    220 
    221   UserManager::Get()->SessionStarted();
    222 
    223   // Confirms that magnifier is disabled just after session start.
    224   EXPECT_FALSE(IsMagnifierEnabled());
    225   EXPECT_FALSE(GetScreenMagnifierEnabledFromPref());
    226 }
    227 
    228 IN_PROC_BROWSER_TEST_F(MagnificationManagerTest, PRE_LoginOffToFull) {
    229   // Create a new profile once, to run the test with non-new profile.
    230   PrepareNonNewProfile(kTestUserName);
    231 
    232   // Sets prefs to explicitly enable the magnifier.
    233   SetScreenMagnifierEnabledPref(true);
    234   SetScreenMagnifierTypePref(ash::MAGNIFIER_FULL);
    235   SetFullScreenMagnifierScalePref(2.5);
    236 }
    237 
    238 IN_PROC_BROWSER_TEST_F(MagnificationManagerTest, LoginOffToFull) {
    239   // Disables magnifier on login screen.
    240   SetMagnifierEnabled(false);
    241   EXPECT_FALSE(IsMagnifierEnabled());
    242 
    243   // Logs in (but the session is not started yet).
    244   UserManager::Get()->UserLoggedIn(kTestUserName, kTestUserName, true);
    245 
    246   // Confirms that magnifier is keeping disabled.
    247   EXPECT_FALSE(IsMagnifierEnabled());
    248 
    249   UserManager::Get()->SessionStarted();
    250 
    251   // Confirms that the magnifier is enabled and configured according to the
    252   // explicitly set prefs just after session start.
    253   EXPECT_TRUE(IsMagnifierEnabled());
    254   EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
    255   EXPECT_EQ(2.5, GetFullScreenMagnifierScale());
    256   EXPECT_TRUE(GetScreenMagnifierEnabledFromPref());
    257 }
    258 
    259 IN_PROC_BROWSER_TEST_F(MagnificationManagerTest, PRE_LoginFullToFull) {
    260   // Create a new profile once, to run the test with non-new profile.
    261   PrepareNonNewProfile(kTestUserName);
    262 
    263   // Sets prefs to explicitly enable the magnifier.
    264   SetScreenMagnifierEnabledPref(true);
    265   SetScreenMagnifierTypePref(ash::MAGNIFIER_FULL);
    266   SetFullScreenMagnifierScalePref(2.5);
    267 }
    268 
    269 IN_PROC_BROWSER_TEST_F(MagnificationManagerTest, LoginFullToFull) {
    270   // Enables magnifier on login screen.
    271   SetMagnifierType(ash::MAGNIFIER_FULL);
    272   SetMagnifierEnabled(true);
    273   SetFullScreenMagnifierScale(3.0);
    274   EXPECT_TRUE(IsMagnifierEnabled());
    275   EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
    276   EXPECT_EQ(3.0, GetFullScreenMagnifierScale());
    277 
    278   // Logs in (but the session is not started yet).
    279   UserManager::Get()->UserLoggedIn(kTestUserName, kTestUserName, true);
    280 
    281   // Confirms that magnifier is keeping enabled.
    282   EXPECT_TRUE(IsMagnifierEnabled());
    283   EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
    284 
    285   UserManager::Get()->SessionStarted();
    286 
    287   // Confirms that the magnifier is enabled and configured according to the
    288   // explicitly set prefs just after session start.
    289   EXPECT_TRUE(IsMagnifierEnabled());
    290   EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
    291   EXPECT_EQ(2.5, GetFullScreenMagnifierScale());
    292   EXPECT_TRUE(GetScreenMagnifierEnabledFromPref());
    293 }
    294 
    295 IN_PROC_BROWSER_TEST_F(MagnificationManagerTest, PRE_LoginFullToUnset) {
    296   // Creates a new profile once, to run the test with non-new profile.
    297   PrepareNonNewProfile(kTestUserName);
    298 }
    299 
    300 IN_PROC_BROWSER_TEST_F(MagnificationManagerTest, LoginFullToUnset) {
    301   // Enables full screen magnifier.
    302   SetMagnifierType(ash::MAGNIFIER_FULL);
    303   SetMagnifierEnabled(true);
    304   EXPECT_TRUE(IsMagnifierEnabled());
    305   EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
    306 
    307   // Logs in (but the session is not started yet).
    308   UserManager::Get()->UserLoggedIn(kTestUserName, kTestUserName, true);
    309 
    310   // Confirms that magnifier is keeping enabled.
    311   EXPECT_TRUE(IsMagnifierEnabled());
    312   EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
    313 
    314   UserManager::Get()->SessionStarted();
    315 
    316   // Confirms that magnifier is disabled.
    317   EXPECT_FALSE(IsMagnifierEnabled());
    318   EXPECT_FALSE(GetScreenMagnifierEnabledFromPref());
    319 }
    320 
    321 IN_PROC_BROWSER_TEST_F(MagnificationManagerTest, LoginAsNewUserOff) {
    322   // Confirms that magnifier is disabled on the login screen.
    323   EXPECT_FALSE(IsMagnifierEnabled());
    324 
    325   // Disables magnifier on login screen explicitly.
    326   SetMagnifierEnabled(false);
    327 
    328   // Logs in (but the session is not started yet).
    329   UserManager::Get()->UserLoggedIn(kTestUserName, kTestUserName, true);
    330 
    331   // Confirms that magnifier is keeping disabled.
    332   EXPECT_FALSE(IsMagnifierEnabled());
    333 
    334   UserManager::Get()->SessionStarted();
    335 
    336   // Confirms that magnifier is keeping disabled.
    337   EXPECT_FALSE(IsMagnifierEnabled());
    338   EXPECT_FALSE(GetScreenMagnifierEnabledFromPref());
    339 }
    340 
    341 IN_PROC_BROWSER_TEST_F(MagnificationManagerTest, LoginAsNewUserFull) {
    342   // Enables magnifier on login screen.
    343   SetMagnifierType(ash::MAGNIFIER_FULL);
    344   SetMagnifierEnabled(true);
    345   SetFullScreenMagnifierScale(2.5);
    346   EXPECT_TRUE(IsMagnifierEnabled());
    347   EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
    348   EXPECT_EQ(2.5, GetFullScreenMagnifierScale());
    349 
    350   // Logs in (but the session is not started yet).
    351   UserManager::Get()->UserLoggedIn(kTestUserName, kTestUserName, true);
    352 
    353   // Confirms that magnifier is keeping enabled.
    354   EXPECT_TRUE(IsMagnifierEnabled());
    355   EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
    356 
    357   UserManager::Get()->SessionStarted();
    358 
    359   // Confirms that magnifier keeps enabled.
    360   EXPECT_TRUE(IsMagnifierEnabled());
    361   EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
    362   EXPECT_EQ(2.5, GetFullScreenMagnifierScale());
    363   EXPECT_TRUE(GetScreenMagnifierEnabledFromPref());
    364 }
    365 
    366 IN_PROC_BROWSER_TEST_F(MagnificationManagerTest, LoginAsNewUserUnset) {
    367   // Confirms that magnifier is disabled on the login screen.
    368   EXPECT_FALSE(IsMagnifierEnabled());
    369 
    370   // Logs in (but the session is not started yet).
    371   UserManager::Get()->UserLoggedIn(kTestUserName, kTestUserName, true);
    372 
    373   // Confirms that magnifier is keeping disabled.
    374   EXPECT_FALSE(IsMagnifierEnabled());
    375 
    376   UserManager::Get()->SessionStarted();
    377 
    378   // Confirms that magnifier is keeping disabled.
    379   EXPECT_FALSE(IsMagnifierEnabled());
    380   EXPECT_FALSE(GetScreenMagnifierEnabledFromPref());
    381 }
    382 
    383 IN_PROC_BROWSER_TEST_F(MagnificationManagerTest, ChangeMagnifierType) {
    384   // Enables/disables full screen magnifier.
    385   SetMagnifierEnabled(false);
    386   SetMagnifierType(ash::MAGNIFIER_FULL);
    387   EXPECT_FALSE(IsMagnifierEnabled());
    388   EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
    389 
    390   SetMagnifierEnabled(true);
    391   EXPECT_TRUE(IsMagnifierEnabled());
    392   EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
    393 
    394   SetMagnifierEnabled(false);
    395   EXPECT_FALSE(IsMagnifierEnabled());
    396   EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
    397 
    398   // Enables/disables partial screen magnifier.
    399   SetMagnifierType(ash::MAGNIFIER_PARTIAL);
    400   EXPECT_FALSE(IsMagnifierEnabled());
    401   EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
    402 
    403   SetMagnifierEnabled(true);
    404   EXPECT_TRUE(IsMagnifierEnabled());
    405   EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
    406 
    407   SetMagnifierEnabled(false);
    408   EXPECT_FALSE(IsMagnifierEnabled());
    409   EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
    410 
    411   // Changes the magnifier type when the magnifier is enabled.
    412   SetMagnifierType(ash::MAGNIFIER_FULL);
    413   SetMagnifierEnabled(true);
    414   EXPECT_TRUE(IsMagnifierEnabled());
    415   EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
    416 
    417   SetMagnifierType(ash::MAGNIFIER_PARTIAL);
    418   EXPECT_TRUE(IsMagnifierEnabled());
    419   EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
    420 
    421   SetMagnifierType(ash::MAGNIFIER_FULL);
    422   EXPECT_TRUE(IsMagnifierEnabled());
    423   EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
    424 
    425   // Changes the magnifier type when the magnifier is disabled.
    426   SetMagnifierEnabled(false);
    427   SetMagnifierType(ash::MAGNIFIER_FULL);
    428   EXPECT_FALSE(IsMagnifierEnabled());
    429   EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
    430 
    431   SetMagnifierType(ash::MAGNIFIER_PARTIAL);
    432   EXPECT_FALSE(IsMagnifierEnabled());
    433   EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
    434 
    435   SetMagnifierType(ash::MAGNIFIER_FULL);
    436   EXPECT_FALSE(IsMagnifierEnabled());
    437   EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
    438 }
    439 
    440 IN_PROC_BROWSER_TEST_F(MagnificationManagerTest, TypePref) {
    441   // Logs in
    442   UserManager::Get()->UserLoggedIn(kTestUserName, kTestUserName, true);
    443   UserManager::Get()->SessionStarted();
    444 
    445   // Confirms that magnifier is disabled just after login.
    446   EXPECT_FALSE(IsMagnifierEnabled());
    447 
    448   // Sets the pref as true to enable magnifier.
    449   SetScreenMagnifierTypePref(ash::MAGNIFIER_FULL);
    450   SetScreenMagnifierEnabledPref(true);
    451   // Confirms that magnifier is enabled.
    452   EXPECT_TRUE(IsMagnifierEnabled());
    453   EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
    454 }
    455 
    456 IN_PROC_BROWSER_TEST_F(MagnificationManagerTest, ScalePref) {
    457   SetMagnifierEnabled(false);
    458   EXPECT_FALSE(IsMagnifierEnabled());
    459 
    460   // Sets 2.5x to the pref.
    461   SetSavedFullScreenMagnifierScale(2.5);
    462 
    463   // Enables full screen magnifier.
    464   SetMagnifierType(ash::MAGNIFIER_FULL);
    465   SetMagnifierEnabled(true);
    466   EXPECT_TRUE(IsMagnifierEnabled());
    467   EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
    468 
    469   // Confirms that 2.5x is restored.
    470   EXPECT_EQ(2.5, GetFullScreenMagnifierScale());
    471 
    472   // Sets the scale and confirms that the scale is saved to pref.
    473   SetFullScreenMagnifierScale(3.0);
    474   EXPECT_EQ(3.0, GetSavedFullScreenMagnifierScale());
    475 }
    476 
    477 IN_PROC_BROWSER_TEST_F(MagnificationManagerTest, InvalidScalePref) {
    478   // TEST 1: Sets too small scale
    479   SetMagnifierEnabled(false);
    480   EXPECT_FALSE(IsMagnifierEnabled());
    481 
    482   // Sets too small value to the pref.
    483   SetSavedFullScreenMagnifierScale(0.5);
    484 
    485   // Enables full screen magnifier.
    486   SetMagnifierType(ash::MAGNIFIER_FULL);
    487   SetMagnifierEnabled(true);
    488   EXPECT_TRUE(IsMagnifierEnabled());
    489   EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
    490 
    491   // Confirms that the actual scale is set to the minimum scale.
    492   EXPECT_EQ(1.0, GetFullScreenMagnifierScale());
    493 
    494   // TEST 2: Sets too large scale
    495   SetMagnifierEnabled(false);
    496   EXPECT_FALSE(IsMagnifierEnabled());
    497 
    498   // Sets too large value to the pref.
    499   SetSavedFullScreenMagnifierScale(50.0);
    500 
    501   // Enables full screen magnifier.
    502   SetMagnifierEnabled(true);
    503   EXPECT_TRUE(IsMagnifierEnabled());
    504   EXPECT_EQ(ash::MAGNIFIER_FULL, GetMagnifierType());
    505 
    506   // Confirms that the actual scale is set to the maximum scale.
    507   EXPECT_EQ(4.0, GetFullScreenMagnifierScale());
    508 }
    509 
    510 }  // namespace chromeos
    511