����JFIFXX�����    $.' ",#(7),01444'9=82<.342  2!!22222222222222222222222222222222222222222222222222����"��4�� ���,�PG"Z_�4�˷����kjز�Z�,F+��_z�,�© �����zh6�٨�ic�fu���#ډb���_�N�?��wQ���5-�~�I���8����TK<5o�Iv-�����k�_U_�����~b�M��d����Ӝ�U�Hh��?]��E�w��Q���k�{��_}qFW7HTՑ��Y��F�?_�'ϔ��_�Ջt��=||I ��6�έ"�����D���/[�k�9���Y�8ds|\���Ҿp6�Ҵ���]��.����6�z<�v��@]�i%��$j��~�g��J>��no����pM[me�i$[����s�o�ᘨ�˸ nɜG-�ĨU�ycP�3.DB�li�;��hj���x7Z^�N�h������N3u{�:j�x�힞��#M&��jL P@_���� P��&��o8������9�����@Sz6�t7#O�ߋ �s}Yf�T���lmr����Z)'N��k�۞p����w\�Tȯ?�8`�O��i{wﭹW�[�r�� ��Q4F�׊���3m&L�=��h3����z~��#�\�l :�F,j@�� ʱ�wQT����8�"kJO���6�֚l����}���R�>ډK���]��y����&����p�}b��;N�1�m�r$�|��7�>e�@B�TM*-iH��g�D�)� E�m�|�ؘbҗ�a��Ҿ����t4���o���G��*oCN�rP���Q��@z,|?W[0�����:�n,jWiE��W��$~/�hp\��?��{(�0���+�Y8rΟ�+����>S-S����VN;�}�s?.����� w�9��˟<���Mq4�Wv'��{)0�1mB��V����W[�����8�/<� �%���wT^�5���b��)iM� pg�N�&ݝ��VO~�q���u���9� ����!��J27����$O-���! �:�%H��� ـ����y�ΠM=t{!S�� oK8������t<����è:a������[�����ա�H���~��w��Qz`�po�^ ����Q��n� �,uu�C�$ ^���,������8�#��:�6��e�|~���!�3�3.�\0��q��o�4`.|� ����y�Q�`~;�d�ׯ,��O�Zw�������`73�v�܋�<���Ȏ�� ـ4k��5�K�a�u�=9Yd��$>x�A�&�� j0� ���vF��� Y�|�y��� ~�6�@c��1vOp�Ig����4��l�OD���L����� R���c���j�_�uX6��3?nk��Wy�f;^*B� ��@�~a�`��Eu������+���6�L��.ü>��}y���}_�O�6�͐�:�YrG�X��kG�����l^w���~㒶sy��Iu�!� W ��X��N�7BV��O��!X�2����wvG�R�f�T#�����t�/?���%8�^�W�aT��G�cL�M���I��(J����1~�8�?aT ���]����AS�E��(��*E}� 2��#I/�׍qz��^t�̔���b�Yz4x���t�){ OH��+(E��A&�N�������XT��o��"�XC��'���)}�J�z�p� ��~5�}�^����+�6����w��c��Q�|Lp�d�H��}�(�.|����k��c4^�"�����Z?ȕ ��a<�L�!039C� �Eu�C�F�Ew�ç ;�n?�*o���B�8�bʝ���'#Rqf���M}7����]����s2tcS{�\icTx;�\��7K���P���ʇ Z O-��~��c>"��?�������P��E��O�8��@�8��G��Q�g�a�Վ���󁶠�䧘��_%#r�>�1�z�a��eb��qcPѵ��n���#L��� =��׀t� L�7�`��V���A{�C:�g���e@�w1 Xp3�c3�ġ����p��M"'-�@n4���fG��B3�DJ�8[Jo�ߐ���gK)ƛ��$���� ���8�3�����+���� �����6�ʻ���� ���S�kI�*KZlT _`���?��K����QK�d����B`�s}�>���`��*�>��,*@J�d�oF*����弝��O}�k��s��]��y�ߘ��c1G�V���<=�7��7����6�q�PT��tXԀ�!9*4�4Tހ3XΛex�46���Y��D ����� �BdemDa����\�_l,��G�/���֌7���Y�](�xTt^%�GE�����4�}bT���ڹ�����;Y)���B�Q��u��>J/J �⮶.�XԄ��j�ݳ�+E��d ��r�5�_D�1 ��o�� �B�x�΢�#���<��W�����8���R6�@g�M�.��� dr�D��>(otU��@x=��~v���2� ӣ�d�oBd��3�eO�6�㣷�����ݜ6��6Y��Qz`��S��{���\P�~z m5{J/L��1������<�e�ͅPu�b�]�ϔ���'������f�b� Zpw��c`"��i���BD@:)ִ�:�]��hv�E�w���T�l��P���"Ju�}��وV J��G6��. J/�Qgl߭�e�����@�z�Zev2u�)]կ�����7x���s�M�-<ɯ�c��r�v�����@��$�ޮ}lk���a���'����>x��O\�ZFu>�����ck#��&:��`�$�ai�>2Δ����l���oF[h��lE�ܺ�Πk:)���`�� $[6�����9�����kOw�\|���8}������ބ:��񶐕��I�A1/�=�2[�,�!��.}gN#�u����b��� ~��݊��}34q����d�E��Lc��$��"�[q�U�硬g^��%B �z���r�pJ�ru%v\h1Y�ne`ǥ:g���pQM~�^�Xi� ��`S�:V29.�P���V�?B�k�� AEvw%�_�9C�Q����wKekPؠ�\�;Io d�{ ߞo�c1eP����\� `����E=���@K<�Y���eڼ�J���w����{av�F�'�M�@/J��+9p���|]�����Iw &`��8���&M�hg��[�{��Xj��%��Ӓ�$��(����ʹN���<>�I���RY���K2�NPlL�ɀ)��&e����B+ь����( � �JTx���_?EZ� }@ 6�U���뙢ط�z��dWI�n` D����噥�[��uV��"�G&Ú����2g�}&m��?ċ�"����Om#��������� ��{�ON��"S�X��Ne��ysQ���@Fn��Vg���dX�~nj�]J�<�K]:��FW��b�������62�=��5f����JKw��bf�X�55��~J �%^����:�-�QIE��P��v�nZum� z � ~ə ���� ���ة����;�f��\v���g�8�1��f24;�V���ǔ�)����9���1\��c��v�/'Ƞ�w�������$�4�R-��t���� e�6�/�ġ �̕Ecy�J���u�B���<�W�ַ~�w[B1L۲�-JS΂�{���΃������A��20�c#��@ 0!1@AP"#2Q`$3V�%45a6�FRUq��� ����^7ׅ,$n�������+��F�`��2X'��0vM��p�L=������5��8������u�p~���.�`r�����\���O��,ư�0oS ��_�M�����l���4�kv\JSd���x���SW�<��Ae�IX����������$I���w�:S���y���›R��9�Q[���,�5�;�@]�%���u�@ *ro�lbI �� ��+���%m:�͇ZV�����u�̉����θau<�fc�.����{�4Ա� �Q����*�Sm��8\ujqs]{kN���)qO�y�_*dJ�b�7���yQqI&9�ԌK!�M}�R�;������S�T���1���i[U�ɵz�]��U)V�S6���3$K{�ߊ<�(� E]Զ[ǼENg�����'�\?#)Dkf��J���o��v���'�%ƞ�&K�u�!��b�35LX�Ϸ��63$K�a�;�9>,R��W��3�3� d�JeTYE.Mϧ��-�o�j3+y��y^�c�������VO�9NV\nd�1 ��!͕_)a�v;����թ�M�lWR1��)El��P;��yوÏ�u 3�k�5Pr6<�⒲l�!˞*��u־�n�!�l:����UNW ��%��Chx8vL'��X�@��*��)���̮��ˍ��� ���D-M�+J�U�kvK����+�x8��cY������?�Ԡ��~3mo��|�u@[XeY�C�\Kp�x8�oC�C�&����N�~3-H���� ��MX�s�u<`���~"WL��$8ξ��3���a�)|:@�m�\���^�`�@ҷ)�5p+��6���p�%i)P M���ngc�����#0Aruz���RL+xSS?���ʮ}()#�t��mˇ!��0}}y����<�e� �-ή�Ԩ��X������ MF���ԙ~l L.3���}�V뽺�v�����멬��Nl�)�2����^�Iq��a��M��qG��T�����c3#������3U�Ǎ���}��לS�|qa��ڃ�+���-��2�f����/��bz��ڐ�� �ݼ[2�ç����k�X�2�* �Z�d���J�G����M*9W���s{��w���T��x��y,�in�O�v��]���n����P�$�JB@=4�OTI�n��e�22a\����q�d���%�$��(���:���: /*�K[PR�fr\nڙdN���F�n�$�4�[�� U�zƶ����� �mʋ���,�ao�u 3�z� �x��Kn����\[��VFmbE;�_U��&V�Gg�]L�۪&#n%�$ɯ�dG���D�TI=�%+AB�Ru#��b4�1�»x�cs�YzڙJG��f��Il��d�eF'T� iA��T���uC�$����Y��H?����[!G`}���ͪ� �纤Hv\������j�Ex�K���!���OiƸ�Yj�+u-<���'q����uN�*�r\��+�]���<�wOZ.fp�ێ��,-*)V?j-kÊ#�`�r��dV����(�ݽBk�����G�ƛk�QmUڗe��Z���f}|����8�8��a���i��3'J�����~G_�^���d�8w������ R�`(�~�.��u���l�s+g�bv���W���lGc}��u���afE~1�Ue������Z�0�8�=e�� f@/�jqEKQQ�J��oN��J���W5~M>$6�Lt�;$ʳ{���^��6�{����v6���ķܰg�V�cnn �~z�x�«�,2�u�?cE+Ș�H؎�%�Za�)���X>uW�Tz�Nyo����s���FQƤ��$��*�&�LLXL)�1�" L��eO��ɟ�9=���:t��Z���c��Ž���Y?�ӭV�wv�~,Y��r�ۗ�|�y��GaF�����C�����.�+� ���v1���fήJ�����]�S��T��B��n5sW}y�$��~z�'�c ��8 ��� ,! �p��VN�S��N�N�q��y8z˱�A��4��*��'������2n<�s���^ǧ˭P�Jޮɏ�U�G�L�J�*#��<�V��t7�8����TĜ>��i}K%,���)[��z�21z ?�N�i�n1?T�I�R#��m-�����������������1����lA�`��fT5+��ܐ�c�q՝��ʐ��,���3�f2U�եmab��#ŠdQ�y>\��)�SLY����w#��.���ʑ�f��� ,"+�w�~�N�'�c�O�3F�������N<���)j��&��,-� �љ���֊�_�zS���TǦ����w�>��?�������n��U仆�V���e�����0���$�C�d���rP �m�׈e�Xm�Vu� �L��.�bֹ��� �[Դaզ���*��\y�8�Է:�Ez\�0�Kq�C b��̘��cө���Q��=0Y��s�N��S.���3.���O�o:���#���v7�[#߫ ��5�܎�L���Er4���9n��COWlG�^��0k�%<���ZB���aB_���������'=��{i�v�l�$�uC���mƎҝ{�c㱼�y]���W�i ��ߧc��m�H� m�"�"�����;Y�ߝ�Z�Ǔ�����:S#��|}�y�,/k�Ld� TA�(�AI$+I3��;Y*���Z��}|��ӧO��d�v��..#:n��f>�>���ȶI�TX��� 8��y����"d�R�|�)0���=���n4��6ⲑ�+��r<�O�܂~zh�z����7ܓ�HH�Ga롏���nCo�>������a ���~]���R���̲c?�6(�q�;5%� |�uj�~z8R=X��I�V=�|{v�Gj\gc��q����z�؋%M�ߍ����1y��#��@f^���^�>N�����#x#۹��6�Y~�?�dfPO��{��P�4��V��u1E1J �*|���%���JN��`eWu�zk M6���q t[�� ��g�G���v��WIG��u_ft����5�j�"�Y�:T��ɐ���*�;� e5���4����q$C��2d�}���� _S�L#m�Yp��O�.�C�;��c����Hi#֩%+) �Ӎ��ƲV���SYź��g |���tj��3�8���r|���V��1#;.SQ�A[���S������#���`n�+���$��$I �P\[�@�s��(�ED�z���P��])8�G#��0B��[ى��X�II�q<��9�~[Z멜�Z�⊔IWU&A>�P~�#��dp<�?����7���c��'~���5 ��+$���lx@�M�dm��n<=e�dyX��?{�|Aef ,|n3�<~z�ƃ�uۧ�����P��Y,�ӥQ�*g�#먙R�\���;T��i,��[9Qi歉����c>]9�� ��"�c��P�� �Md?٥��If�ت�u��k��/����F��9�c*9��Ǎ:�ØF���z�n*�@|I�ށ9����N3{'��[�'ͬ�Ҳ4��#}��!�V� Fu��,�,mTIk���v C�7v���B�6k�T9��1�*l� '~��ƞF��lU��'�M ����][ΩũJ_�{�i�I�n��$���L�� j��O�dx�����kza۪��#�E��Cl����x˘�o�����V���ɞ�ljr��)�/,�߬h�L��#��^��L�ф�,íMƁe�̩�NB�L�����iL����q�}��(��q��6IçJ$�W�E$��:������=#����(�K�B����zђ <��K(�N�۫K�w��^O{!����)�H���>x�������lx�?>Պ�+�>�W���,Ly!_�D���Ō�l���Q�!�[ �S����J��1��Ɛ�Y}��b,+�Lo�x�ɓ)����=�y�oh�@�꥟/��I��ѭ=��P�y9��� �ۍYӘ�e+�p�Jnϱ?V\SO%�(�t� ���=?MR�[Ș�����d�/ ��n�l��B�7j� ��!�;ӥ�/�[-���A�>�dN�sLj ��,ɪv��=1c�.SQ�O3�U���ƀ�ܽ�E����������̻��9G�ϷD�7(�}��Ävӌ\�y�_0[w ���<΍>����a_��[0+�L��F.�޺��f�>oN�T����q;���y\��bՃ��y�jH�<|q-eɏ�_?_9+P���Hp$�����[ux�K w�Mw��N�ی'$Y2�=��q���KB��P��~������Yul:�[<����F1�2�O���5=d����]Y�sw:���Ϯ���E��j,_Q��X��z`H1,#II ��d�wr��P˂@�ZJV����y$�\y�{}��^~���[:N����ߌ�U�������O��d�����ؾe��${p>G��3c���Ė�lʌ�� ת��[��`ϱ�-W����dg�I��ig2��� ��}s ��ؤ(%#sS@���~���3�X�nRG�~\jc3�v��ӍL��M[JB�T��s3}��j�Nʖ��W����;7��ç?=X�F=-�=����q�ߚ���#���='�c��7���ڑW�I(O+=:uxq�������������e2�zi+�kuG�R��������0�&e�n���iT^J����~\jy���p'dtG��s����O��3����9* �b#Ɋ�� p������[Bws�T�>d4�ۧs���nv�n���U���_�~,�v����ƜJ1��s�� �QIz��)�(lv8M���U=�;����56��G���s#�K���MP�=��LvyGd��}�VwWBF�'�à �?MH�U�g2�� ����!�p�7Q��j��ڴ����=��j�u��� Jn�A s���uM������e��Ɔ�Ҕ�!)'��8Ϣ�ٔ��ޝ(��Vp���צ֖d=�IC�J�Ǡ{q������kԭ�߸���i��@K����u�|�p=..�*+����x�����z[Aqġ#s2a�Ɗ���RR�)*HRsi�~�a &f��M��P����-K�L@��Z��Xy�'x�{}��Zm+���:�)�) IJ�-i�u���� ���ܒH��'�L(7�y�GӜq���� j��� 6ߌg1�g�o���,kر���tY�?W,���p���e���f�OQS��!K�۟cҒA�|ս�j�>��=⬒��˧L[�� �߿2JaB~R��u�:��Q�] �0H~���]�7��Ƽ�I���(}��cq '�ήET���q�?f�ab���ӥvr� �)o��-Q��_'����ᴎo��K������;��V���o��%���~OK ����*��b�f:���-ťIR��`B�5!RB@���ï�� �u �̯e\�_U�_������� g�ES��3�������QT��a����x����U<~�c?�*�#]�MW,[8O�a�x��]�1bC|踤�P��lw5V%�)�{t�<��d��5���0i�XSU��m:��Z�┵�i�"��1�^B�-��P�hJ��&)O��*�D��c�W��vM��)����}���P��ܗ-q����\mmζZ-l@�}��a��E�6��F�@��&Sg@���ݚ�M����� ȹ 4����#p�\H����dYDo�H���"��\��..R�B�H�z_�/5˘����6��KhJR��P�mƶi�m���3�,#c�co��q�a)*Pt����R�m�k�7x�D�E�\Y�閣_X�<���~�)���c[[�BP����6�Yq���S��0����%_����;��Àv�~�| VS؇ ��'O0��F0��\���U�-�d@�����7�SJ*z��3n��y��P����O���������m�~�P�3|Y��ʉr#�C�<�G~�.,! ���bqx���h~0=��!ǫ�jy����l�O,�[B��~��|9��ٱ����Xly�#�i�B��g%�S��������tˋ���e���ې��\[d�t)��.+u�|1 ������#�~Oj����hS�%��i.�~X���I�H�m��0n���c�1uE�q��cF�RF�o���7� �O�ꮧ� ���ۛ{��ʛi5�rw?׌#Qn�TW��~?y$��m\�\o����%W� ?=>S�N@�� �Ʈ���R����N�)�r"C�:��:����� �����#��qb��Y�. �6[��2K����2u�Ǧ�HYR��Q�MV��� �G�$��Q+.>�����nNH��q�^��� ����q��mM��V��D�+�-�#*�U�̒ ���p욳��u:�������IB���m���PV@O���r[b= �� ��1U�E��_Nm�yKbN�O���U�}�the�`�|6֮P>�\2�P�V���I�D�i�P�O;�9�r�mAHG�W�S]��J*�_�G��+kP�2����Ka�Z���H�'K�x�W�MZ%�O�YD�Rc+o��?�q��Ghm��d�S�oh�\�D�|:W������UA�Qc yT�q������~^�H��/��#p�CZ���T�I�1�ӏT����4��"�ČZ�����}��`w�#�*,ʹ�� ��0�i��課�Om�*�da��^gJ݅{���l�e9uF#T�ֲ��̲�ٞC"�q���ߍ ոޑ�o#�XZTp����@ o�8��(jd��xw�]�,f���`~�|,s��^����f�1���t��|��m�򸄭/ctr��5s��7�9Q�4�H1꠲BB@l9@���C�����+�wp�xu�£Yc�9��?`@#�o�mH�s2��)�=��2�.�l����jg�9$�Y�S�%*L������R�Y������7Z���,*=�䷘$�������arm�o�ϰ���UW.|�r�uf����IGw�t����Zwo��~5 ��YյhO+=8fF�)�W�7�L9lM�̘·Y���֘YLf�큹�pRF���99.A �"wz��=E\Z���'a� 2��Ǚ�#;�'}�G���*��l��^"q��+2FQ� hj��kŦ��${���ޮ-�T�٭cf�|�3#~�RJ����t��$b�(R��(����r���dx� >U b�&9,>���%E\� Ά�e�$��'�q't��*�א���ެ�b��-|d���SB�O�O��$�R+�H�)�܎�K��1m`;�J�2�Y~9��O�g8=vqD`K[�F)k�[���1m޼c��n���]s�k�z$@��)!I �x՝"v��9=�ZA=`Ɠi �:�E��)`7��vI��}d�YI�_ �o�:ob���o ���3Q��&D&�2=�� �Ά��;>�h����y.*ⅥS������Ӭ�+q&����j|UƧ����}���J0��WW< ۋS�)jQR�j���Ư��rN)�Gű�4Ѷ(�S)Ǣ�8��i��W52���No˓� ۍ%�5brOn�L�;�n��\G����=�^U�dI���8$�&���h��'���+�(������cȁ߫k�l��S^���cƗjԌE�ꭔ��gF���Ȓ��@���}O���*;e�v�WV���YJ\�]X'5��ղ�k�F��b 6R�o՜m��i N�i����>J����?��lPm�U��}>_Z&�KK��q�r��I�D�Չ~�q�3fL�:S�e>���E���-G���{L�6p�e,8��������QI��h��a�Xa��U�A'���ʂ���s�+טIjP�-��y�8ۈZ?J$��W�P� ��R�s�]��|�l(�ԓ��sƊi��o(��S0��Y� 8�T97.�����WiL��c�~�dxc�E|�2!�X�K�Ƙਫ਼�$((�6�~|d9u+�qd�^3�89��Y�6L�.I�����?���iI�q���9�)O/뚅����O���X��X�V��ZF[�یgQ�L��K1���RҖr@v�#��X�l��F���Нy�S�8�7�kF!A��sM���^rkp�jP�DyS$N���q��nxҍ!U�f�!eh�i�2�m���`�Y�I�9r�6� �TF���C}/�y�^���Η���5d�'��9A-��J��>{�_l+�`��A���[�'��յ�ϛ#w:݅�%��X�}�&�PSt�Q�"�-��\縵�/����$Ɨh�Xb�*�y��BS����;W�ջ_mc�����vt?2}1�;qS�d�d~u:2k5�2�R�~�z+|HE!)�Ǟl��7`��0�<�,�2*���Hl-��x�^����'_TV�gZA�'j� ^�2Ϊ��N7t�����?w�� �x1��f��Iz�C-Ȗ��K�^q�;���-W�DvT�7��8�Z�������� hK�(P:��Q- �8�n�Z���܃e貾�<�1�YT<�,�����"�6{/ �?�͟��|1�:�#g��W�>$����d��J��d�B��=��jf[��%rE^��il:��B���x���Sּ�1հ��,�=��*�7 fcG��#q� �eh?��2�7�����,�!7x��6�n�LC�4x��},Geǝ�tC.��vS �F�43��zz\��;QYC,6����~;RYS/6���|2���5���v��T��i����������mlv��������&� �nRh^ejR�LG�f���? �ۉҬܦƩ��|��Ȱ����>3����!v��i�ʯ�>�v��オ�X3e���_1z�Kȗ\<������!�8���V��]��?b�k41�Re��T�q��mz��TiOʦ�Z��Xq���L������q"+���2ۨ��8}�&N7XU7Ap�d�X��~�׿��&4e�o�F��� �H����O���č�c�� 懴�6���͉��+)��v;j��ݷ�� �UV�� i��� j���Y9GdÒJ1��詞�����V?h��l����l�cGs�ځ�������y�Ac�����\V3�? �� ܙg�>qH�S,�E�W�[�㺨�uch�⍸�O�}���a��>�q�6�n6����N6�q������N ! 1AQaq�0@����"2BRb�#Pr���3C`��Scst���$4D���%Td�� ?���N����a��3��m���C���w��������xA�m�q�m���m������$����4n淿t'��C"w��zU=D�\R+w�p+Y�T�&�պ@��ƃ��3ޯ?�Aﶂ��aŘ���@-�����Q�=���9D��ռ�ѻ@��M�V��P��܅�G5�f�Y<�u=,EC)�<�Fy'�"�&�չ�X~f��l�KԆV��?�� �W�N����=(� �;���{�r����ٌ�Y���h{�١������jW����P���Tc�����X�K�r��}���w�R��%��?���E��m�� �Y�q|����\lEE4���r���}�lsI�Y������f�$�=�d�yO����p�����yBj8jU�o�/�S��?�U��*������ˍ�0������u�q�m [�?f����a�� )Q�>����6#������� ?����0UQ����,IX���(6ڵ[�DI�MNލ�c&���υ�j\��X�R|,4��� j������T�hA�e��^���d���b<����n�� �즇�=!���3�^�`j�h�ȓr��jẕ�c�,ٞX����-����a�ﶔ���#�$��]w�O��Ӫ�1y%��L�Y<�wg#�ǝ�̗`�x�xa�t�w��»1���o7o5��>�m뭛C���Uƃߜ}�C���y1Xνm�F8�jI���]����H���ۺиE@I�i;r�8ӭ����V�F�Շ| ��&?�3|x�B�MuS�Ge�=Ӕ�#BE5G�����Y!z��_e��q�р/W>|-�Ci߇�t�1ޯќd�R3�u��g�=0 5��[?�#͏��q�cf���H��{ ?u�=?�?ǯ���}Z��z���hmΔ�BFTW�����<�q�(v� ��!��z���iW]*�J�V�z��gX֧A�q�&��/w���u�gYӘa���; �i=����g:��?2�dž6�ى�k�4�>�Pxs����}������G�9��3 ���)gG�R<>r h�$��'nc�h�P��Bj��J�ҧH� -��N1���N��?��~��}-q!=��_2hc�M��l�vY%UE�@|�v����M2�.Y[|y�"Eï��K�ZF,�ɯ?,q�?v�M 80jx�"�;�9vk�����+ ֧�� �ȺU��?�%�vcV��mA�6��Qg^M����A}�3�nl� QRN�l8�kkn�'�����(��M�7m9و�q���%ޟ���*h$Zk"��$�9��: �?U8�Sl��,,|ɒ��xH(ѷ����Gn�/Q�4�P��G�%��Ա8�N��!� �&�7�;���eKM7�4��9R/%����l�c>�x;������>��C�:�����t��h?aKX�bhe�ᜋ^�$�Iհ �hr7%F$�E��Fd���t��5���+�(M6�t����Ü�UU|zW�=a�Ts�Tg������dqP�Q����b'�m���1{|Y����X�N��b �P~��F^F:����k6�"�j!�� �I�r�`��1&�-$�Bevk:y���#yw��I0��x��=D�4��tU���P�ZH��ڠ底taP��6����b>�xa����Q�#� WeF��ŮNj�p�J* mQ�N����*I�-*�ȩ�F�g�3 �5��V�ʊ�ɮ�a��5F���O@{���NX��?����H�]3��1�Ri_u��������ѕ�� ����0��� F��~��:60�p�͈�S��qX#a�5>���`�o&+�<2�D����: �������ڝ�$�nP���*)�N�|y�Ej�F�5ټ�e���ihy�Z �>���k�bH�a�v��h�-#���!�Po=@k̆IEN��@��}Ll?j�O������߭�ʞ���Q|A07x���wt!xf���I2?Z��<ץ�T���cU�j��]��陎Ltl �}5�ϓ��$�,��O�mˊ�;�@O��jE��j(�ا,��LX���LO���Ц�90�O �.����a��nA���7������j4 ��W��_ٓ���zW�jcB������y՗+EM�)d���N�g6�y1_x��p�$Lv:��9�"z��p���ʙ$��^��JԼ*�ϭ����o���=x�Lj�6�J��u82�A�H�3$�ٕ@�=Vv�]�'�qEz�;I˼��)��=��ɯ���x �/�W(V���p�����$ �m�������u�����񶤑Oqˎ�T����r��㠚x�sr�GC��byp�G��1ߠ�w e�8�$⿄����/�M{*}��W�]˷.�CK\�ުx���/$�WPw���r� |i���&�}�{�X� �>��$-��l���?-z���g����lΆ���(F���h�vS*���b���߲ڡn,|)mrH[���a�3�ר�[1��3o_�U�3�TC�$��(�=�)0�kgP���� ��u�^=��4 �WYCҸ:��vQ�ר�X�à��tk�m,�t*��^�,�}D*� �"(�I��9R����>`�`��[~Q]�#af��i6l��8���6�:,s�s�N6�j"�A4���IuQ��6E,�GnH��zS�HO�uk�5$�I�4��ؤ�Q9�@��C����wp�BGv[]�u�Ov���0I4���\��y�����Q�Ѹ��~>Z��8�T��a��q�ޣ;z��a���/��S��I:�ܫ_�|������>=Z����8:�S��U�I�J��"IY���8%b8���H��:�QO�6�;7�I�S��J��ҌAά3��>c���E+&jf$eC+�z�;��V����� �r���ʺ������my�e���aQ�f&��6�ND��.:��NT�vm�<- u���ǝ\MvZY�N�NT��-A�>jr!S��n�O 1�3�Ns�%�3D@���`������ܟ 1�^c<���� �a�ɽ�̲�Xë#�w�|y�cW�=�9I*H8�p�^(4���՗�k��arOcW�tO�\�ƍR��8����'�K���I�Q�����?5�>[�}��yU�ײ -h��=��% q�ThG�2�)���"ו3]�!kB��*p�FDl�A���,�eEi�H�f�Ps�����5�H:�Փ~�H�0Dت�D�I����h�F3�������c��2���E��9�H��5�zԑ�ʚ�i�X�=:m�xg�hd(�v����׊�9iS��O��d@0ڽ���:�p�5�h-��t�&���X�q�ӕ,��ie�|���7A�2���O%P��E��htj��Y1��w�Ѓ!����  ���� ࢽ��My�7�\�a�@�ţ�J �4�Ȼ�F�@o�̒?4�wx��)��]�P��~�����u�����5�����7X ��9��^ܩ�U;Iꭆ 5 �������eK2�7(�{|��Y׎ �V��\"���Z�1� Z�����}��(�Ǝ"�1S���_�vE30>���p;� ΝD��%x�W�?W?v����o�^V�i�d��r[��/&>�~`�9Wh��y�;���R��� ;;ɮT��?����r$�g1�K����A��C��c��K��l:�'��3 c�ﳯ*"t8�~l��)���m��+U,z��`(�>yJ�?����h>��]��v��ЍG*�{`��;y]��I�T� ;c��NU�fo¾h���/$���|NS���1�S�"�H��V���T���4��uhǜ�]�v;���5�͠x��'C\�SBpl���h}�N����� A�Bx���%��ޭ�l��/����T��w�ʽ]D�=����K���ž�r㻠l4�S�O?=�k �M:� ��c�C�a�#ha���)�ѐxc�s���gP�iG��{+���x���Q���I= �� z��ԫ+ �8"�k�ñ�j=|����c ��y��CF��/��*9ж�h{ �?4�o� ��k�m�Q�N�x��;�Y��4膚�a�w?�6�>e]�����Q�r�:����g�,i"�����ԩA�*M�<�G��b�if��l^M��5� �Ҩ�{����6J��ZJ�����P�*�����Y���ݛu�_4�9�I8�7���������,^ToR���m4�H��?�N�S�ѕw��/S��甍�@�9H�S�T��t�ƻ���ʒU��*{Xs�@����f�����֒Li�K{H�w^���������Ϥm�tq���s� ���ք��f:��o~s��g�r��ט� �S�ѱC�e]�x���a��) ���(b-$(�j>�7q�B?ӕ�F��hV25r[7 Y� }L�R��}����*sg+��x�r�2�U=�*'WS��ZDW]�WǞ�<��叓���{�$�9Ou4��y�90-�1�'*D`�c�^o?(�9��u���ݐ��'PI&� f�Jݮ�������:wS����jfP1F:X �H�9dԯ���˝[�_54 �}*;@�ܨ�� ð�yn�T���?�ןd�#���4rG�ͨ��H�1�|-#���Mr�S3��G�3�����)�.᧏3v�z֑��r����$G"�`j �1t��x0<Ɔ�Wh6�y�6��,œ�Ga��gA����y��b��)��h�D��ß�_�m��ü �gG;��e�v��ݝ�nQ� ��C����-�*��o���y�a��M��I�>�<���]obD��"�:���G�A��-\%LT�8���c�)��+y76���o�Q�#*{�(F�⽕�y����=���rW�\p���۩�c���A���^e6��K������ʐ�cVf5$�'->���ՉN"���F�"�UQ@�f��Gb~��#�&�M=��8�ט�JNu9��D��[̤�s�o�~������ G��9T�tW^g5y$b��Y'��س�Ǵ�=��U-2 #�MC�t(�i� �lj�@Q 5�̣i�*�O����s�x�K�f��}\��M{E�V�{�υ��Ƈ�����);�H����I��fe�Lȣr�2��>��W�I�Ȃ6������i��k�� �5�YOxȺ����>��Y�f5'��|��H+��98pj�n�.O�y�������jY��~��i�w'������l�;�s�2��Y��:'lg�ꥴ)o#'Sa�a�K��Z� �m��}�`169�n���"���x��I ��*+� }F<��cГ���F�P�������ֹ*�PqX�x۩��,� ��N�� �4<-����%����:��7����W���u�`����� $�?�I��&����o��o��`v�>��P��"��l���4��5'�Z�gE���8���?��[�X�7(��.Q�-��*���ތL@̲����v��.5���[��=�t\+�CNܛ��,g�SQnH����}*F�G16���&:�t��4ُ"A��̣��$�b �|����#rs��a�����T�� ]�<�j��BS�('$�ɻ� �wP;�/�n��?�ݜ��x�F��yUn�~mL*-�������Xf�wd^�a�}��f�,=t�׵i�.2/wpN�Ep8�OР���•��R�FJ� 55TZ��T �ɭ�<��]��/�0�r�@�f��V��V����Nz�G��^���7hZi����k��3�,kN�e|�vg�1{9]_i��X5y7� 8e]�U����'�-2,���e"����]ot�I��Y_��n�(JҼ��1�O ]bXc���Nu�No��pS���Q_���_�?i�~�x h5d'�(qw52] ��'ޤ�q��o1�R!���`ywy�A4u���h<קy���\[~�4�\ X�Wt/� 6�����n�F�a8��f���z �3$�t(���q��q�x��^�XWeN'p<-v�!�{�(>ӽDP7��ո0�y)�e$ٕv�Ih'Q�EA�m*�H��RI��=:��� ���4牢) �%_iN�ݧ�l]� �Nt���G��H�L��� ɱ�g<���1V�,�J~�ٹ�"K��Q�� 9�HS�9�?@��k����r�;we݁�]I�!{ �@�G�[�"��`���J:�n]�{�cA�E����V��ʆ���#��U9�6����j�#Y�m\��q�e4h�B�7��C�������d<�?J����1g:ٳ���=Y���D�p�ц� ׈ǔ��1�]26؜oS�'��9�V�FVu�P�h�9�xc�oq�X��p�o�5��Ա5$�9W�V(�[Ak�aY錎qf;�'�[�|���b�6�Ck��)��#a#a˙��8���=äh�4��2��C��4tm^ �n'c���]GQ$[Wҿ��i���vN�{Fu ��1�gx��1┷���N�m��{j-,��x�� Ūm�ЧS�[�s���Gna���䑴�� x�p 8<������97�Q���ϴ�v�aϚG��Rt�Һ׈�f^\r��WH�JU�7Z���y)�vg=����n��4�_)y��D'y�6�]�c�5̪�\� �PF�k����&�c;��cq�$~T�7j ���nç]�<�g ":�to�t}�159�<�/�8������m�b�K#g'I'.W�����6��I/��>v��\�MN��g���m�A�yQL�4u�Lj�j9��#44�t��l^�}L����n��R��!��t��±]��r��h6ٍ>�yҏ�N��fU�� ���� Fm@�8}�/u��jb9������he:A�y�ծw��GpΧh�5����l}�3p468��)U��d��c����;Us/�֔�YX�1�O2��uq�s��`hwg�r~�{ R��mhN��؎*q 42�*th��>�#���E����#��Hv�O����q�}�����6�e��\�,Wk�#���X��b>��p}�դ��3���T5��†��6��[��@�P�y*n��|'f�֧>�lư΂�̺����SU�'*�q�p�_S�����M�� '��c�6�����m�� ySʨ;M��r���Ƌ�m�Kxo,���Gm�P��A�G�:��i��w�9�}M(�^�V��$ǒ�ѽ�9���|���� �a����J�SQ�a���r�B;����}���ٻ֢�2�%U���c�#�g���N�a�ݕ�'�v�[�OY'��3L�3�;,p�]@�S��{ls��X�'���c�jw�k'a�.��}�}&�� �dP�*�bK=ɍ!����;3n�gΊU�ߴmt�'*{,=SzfD� A��ko~�G�aoq�_mi}#�m�������P�Xhύ����mxǍ�΂���巿zf��Q���c���|kc�����?���W��Y�$���_Lv����l߶��c���`?����l�j�ݲˏ!V��6����U�Ђ(A���4y)H���p�Z_�x��>���e��R��$�/�`^'3qˏ�-&Q�=?��CFVR �D�fV�9��{�8g�������n�h�(P"��6�[�D���< E�����~0<@�`�G�6����Hг�cc�� �c�K.5��D��d�B���`?�XQ��2��ٿyqo&+�1^� DW�0�ꊩ���G�#��Q�nL3��c���������/��x ��1�1[y�x�პCW��C�c�UĨ80�m�e�4.{�m��u���I=��f�����0QRls9���f���������9���~f�����Ǩ��a�"@�8���ȁ�Q����#c�ic������G��$���G���r/$W�(��W���V�"��m�7�[m�A�m����bo��D� j����۳� l���^�k�h׽����� ��#� iXn�v��eT�k�a�^Y�4�BN��ĕ��0 !01@Q"2AaPq3BR������?���@4�Q�����T3,���㺠�W�[=JK�Ϟ���2�r^7��vc�:�9 �E�ߴ�w�S#d���Ix��u��:��Hp��9E!�� V 2;73|F��9Y���*ʬ�F��D����u&���y؟��^EA��A��(ɩ���^��GV:ݜDy�`��Jr29ܾ�㝉��[���E;Fzx��YG��U�e�Y�C���� ����v-tx����I�sם�Ę�q��Eb�+P\ :>�i�C'�;�����k|z�رn�y]�#ǿb��Q��������w�����(�r|ӹs��[�D��2v-%��@;�8<a���[\o[ϧw��I!��*0�krs)�[�J9^��ʜ��p1)� "��/_>��o��<1����A�E�y^�C��`�x1'ܣn�p��s`l���fQ��):�l����b>�Me�jH^?�kl3(�z:���1ŠK&?Q�~�{�ٺ�h�y���/�[��V�|6��}�KbX����mn[-��7�5q�94�������dm���c^���h� X��5��<�eޘ>G���-�}�دB�ޟ� ��|�rt�M��V+�]�c?�-#ڛ��^ǂ}���Lkr���O��u�>�-D�ry� D?:ޞ�U��ǜ�7�V��?瓮�"�#���r��չģVR;�n���/_� ؉v�ݶe5d�b9��/O��009�G���5n�W����JpA�*�r9�>�1��.[t���s�F���nQ� V 77R�]�ɫ8����_0<՜�IF�u(v��4��F�k�3��E)��N:��yڮe��P�`�1}�$WS��J�SQ�N�j�ٺ��޵�#l���ј(�5=��5�lǏmoW�v-�1����v,W�mn��߀$x�<����v�j(����c]��@#��1������Ǔ���o'��u+����;G�#�޸��v-lη��/(`i⣍Pm^���ԯ̾9Z��F��������n��1��� ��]�[��)�'������:�֪�W��FC����� �B9،!?���]��V��A�Վ�M��b�w��G F>_DȬ0¤�#�QR�[V��kz���m�w�"��9ZG�7'[��=�Q����j8R?�zf�\a�=��O�U����*oB�A�|G���2�54 �p��.w7� �� ��&������ξxGHp� B%��$g�����t�Џ򤵍z���HN�u�Я�-�'4��0��;_��3 !01"@AQa2Pq#3BR������?��ʩca��en��^��8���<�u#��m*08r��y�N"�<�Ѳ0��@\�p��� �����Kv�D��J8�Fҽ� �f�Y��-m�ybX�NP����}�!*8t(�OqѢ��Q�wW�K��ZD��Δ^e��!� ��B�K��p~�����e*l}z#9ң�k���q#�Ft�o��S�R����-�w�!�S���Ӥß|M�l޶V��!eˈ�8Y���c�ЮM2��tk���� ������J�fS����Ö*i/2�����n]�k�\���|4yX�8��U�P.���Ы[���l��@"�t�<������5�lF���vU�����W��W��;�b�cД^6[#7@vU�xgZv��F�6��Q,K�v��� �+Ъ��n��Ǣ��Ft���8��0��c�@�!�Zq s�v�t�;#](B��-�nῃ~���3g������5�J�%���O������n�kB�ĺ�.r��+���#�N$?�q�/�s�6��p��a����a��J/��M�8��6�ܰ"�*������ɗud"\w���aT(����[��F��U՛����RT�b���n�*��6���O��SJ�.�ij<�v�MT��R\c��5l�sZB>F��<7�;EA��{��E���Ö��1U/�#��d1�a�n.1ě����0�ʾR�h��|�R��Ao�3�m3 ��%�� ���28Q� ��y��φ���H�To�7�lW>����#i`�q���c����a��� �m,B�-j����݋�'mR1Ήt�>��V��p���s�0IbI�C.���1R�ea�����]H�6����������4B>��o��](��$B���m�����a�!=��?�B� K�Ǿ+�Ծ"�n���K��*��+��[T#�{E�J�S����Q�����s�5�:�U�\wĐ�f�3����܆&�)����I���Ԇw��E T�lrTf6Q|R�h:��[K�� �z��c֧�G�C��%\��_�a�84��HcO�bi��ؖV��7H �)*ģK~Xhչ0��4?�0��� �E<���}3���#���u�?�� ��|g�S�6ꊤ�|�I#Hڛ� �ա��w�X��9��7���Ŀ%�SL��y6č��|�F�a 8���b��$�sק�h���b9RAu7�˨p�Č�_\*w��묦��F ����4D~�f����|(�"m���NK��i�S�>�$d7SlA��/�²����SL��|6N�}���S�˯���g��]6��; �#�.��<���q'Q�1|KQ$�����񛩶"�$r�b:���N8�w@��8$�� �AjfG|~�9F ���Y��ʺ��Bwؒ������M:I岎�G��`s�YV5����6��A �b:�W���G�q%l�����F��H���7�������Fsv7��k�� 403WebShell
403Webshell
Server IP : 14.139.229.36  /  Your IP : 10.1.1.9
Web Server : Apache
System : Linux gbpuat-tech.ac.in 4.18.0-240.15.1.el8_3.x86_64 #1 SMP Mon Mar 1 17:16:16 UTC 2021 x86_64
User : apache ( 48)
PHP Version : 7.2.24
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : ON
Directory :  /proc/thread-self/root/usr/lib64/python3.6/site-packages/pyanaconda/ui/gui/spokes/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /proc/thread-self/root/usr/lib64/python3.6/site-packages/pyanaconda/ui/gui/spokes//network.py
# Network configuration spoke classes
#
# Copyright (C) 2011  Red Hat, Inc.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions of
# the GNU General Public License v.2, or (at your option) any later version.
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY expressed or implied, including the implied warranties of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
# Public License for more details.  You should have received a copy of the
# GNU General Public License along with this program; if not, write to the
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.  Any Red Hat trademarks that are incorporated in the
# source code or documentation are not subject to the GNU General Public
# License and may only be used or replicated with the express permission of
# Red Hat, Inc.
#

import gi
gi.require_version("Gtk", "3.0")
gi.require_version("GObject", "2.0")
gi.require_version("Pango", "1.0")
gi.require_version("Gio", "2.0")
gi.require_version("NM", "1.0")

from gi.repository import Gtk
from gi.repository import GObject, Pango, Gio, NM

from pyanaconda.core.i18n import _, N_, C_, CN_
from pyanaconda.flags import flags as anaconda_flags
from pyanaconda.ui.communication import hubQ
from pyanaconda.ui.gui import GUIObject
from pyanaconda.ui.gui.spokes import NormalSpoke, StandaloneSpoke
from pyanaconda.ui.categories.system import SystemCategory
from pyanaconda.ui.gui.hubs.summary import SummaryHub
from pyanaconda.ui.gui.utils import gtk_call_once, escape_markup, really_hide, really_show
from pyanaconda.ui.common import FirstbootSpokeMixIn
from pyanaconda.core.configuration.anaconda import conf
from pyanaconda.core.util import startProgram
from pyanaconda.core.process_watchers import PidWatcher
from pyanaconda.core.constants import ANACONDA_ENVIRON
from pyanaconda.core import glib
from pyanaconda.modules.common.constants.services import NETWORK
from pyanaconda.modules.common.structures.network import NetworkDeviceConfiguration

from pyanaconda import network

import dbus
import dbus.service
# Used for ascii_letters and hexdigits constants
import string # pylint: disable=deprecated-module
from uuid import uuid4

from dbus.mainloop.glib import DBusGMainLoop
DBusGMainLoop(set_as_default=True)

from pyanaconda.anaconda_loggers import get_module_logger
log = get_module_logger(__name__)

NM._80211ApFlags = getattr(NM, "80211ApFlags")
NM._80211ApSecurityFlags = getattr(NM, "80211ApSecurityFlags")
NM._80211Mode = getattr(NM, "80211Mode")

NM_SERVICE = "org.freedesktop.NetworkManager"
NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION = 0x1
SECRET_AGENT_IFACE = 'org.freedesktop.NetworkManager.SecretAgent'
AGENT_MANAGER_IFACE = 'org.freedesktop.NetworkManager.AgentManager'
AGENT_MANAGER_PATH = "/org/freedesktop/NetworkManager/AgentManager"

IPV4_CONFIG = "IPv4"
IPV6_CONFIG = "IPv6"

DEVICES_COLUMN_ICON_NAME = 0
DEVICES_COLUMN_SORT = 1
DEVICES_COLUMN_TITLE = 2
DEVICES_COLUMN_OBJECT = 3


def localized_string_of_device_state(device, state):
    s = _("Status unknown (missing)")

    if state == NM.DeviceState.UNKNOWN:
        s = _("Status unknown")
    elif state == NM.DeviceState.UNMANAGED:
        s = _("Unmanaged")
    elif state == NM.DeviceState.UNAVAILABLE:
        if not device:
            s = _("Unavailable")
        elif device.get_firmware_missing():
            s = _("Firmware missing")
        else:
            s = _("Unavailable")
    elif state == NM.DeviceState.DISCONNECTED:
        if (device and device.get_device_type() == NM.DeviceType.ETHERNET
              and not device.get_carrier()):
            s = _("Cable unplugged")
        else:
            s = _("Disconnected")
    elif state in (NM.DeviceState.PREPARE,
                   NM.DeviceState.CONFIG,
                   NM.DeviceState.IP_CONFIG,
                   NM.DeviceState.IP_CHECK):
        s = _("Connecting")
    elif state == NM.DeviceState.NEED_AUTH:
        s = _("Authentication required")
    elif state == NM.DeviceState.ACTIVATED:
        s = _("Connected")
    elif state == NM.DeviceState.DEACTIVATING:
        s = _("Disconnecting")
    elif state == NM.DeviceState.FAILED:
        s = _("Connection failed")

    return s


__all__ = ["NetworkSpoke", "NetworkStandaloneSpoke"]


class CellRendererSignal(Gtk.CellRendererPixbuf):

    __gtype_name__ = "CellRendererSignal"
    __gproperties__ = {
        "signal": (GObject.TYPE_UINT,
                   "Signal", "Signal",
                   0, glib.MAXUINT, 0,
                   GObject.ParamFlags.READWRITE),
    }

    def __init__(self):
        super().__init__()
        self.signal = 0

    def do_get_property(self, prop):
        if prop.name == 'signal':
            return self.signal
        else:
            raise AttributeError('unknown property %s' % prop.name)

    def do_set_property(self, prop, value):
        if prop.name == 'signal':
            self.signal = value
            self._set_icon_name(value)
        else:
            raise AttributeError('unknown property %s' % prop.name)

    def _set_icon_name(self, value):

        if value == 0:
            self.set_property("gicon", None)

        if value < 20:
            icon_name = "network-wireless-signal-none-symbolic"
        elif value < 40:
            icon_name = "network-wireless-signal-weak-symbolic"
        elif value < 50:
            icon_name = "network-wireless-signal-ok-symbolic"
        elif value < 80:
            icon_name = "network-wireless-signal-good-symbolic"
        else:
            icon_name = "network-wireless-signal-excellent-symbolic"

        icon = Gio.ThemedIcon.new_with_default_fallbacks(icon_name)
        self.set_property("gicon", icon)


NM_AP_SEC_UNKNOWN = 0
NM_AP_SEC_NONE = 1
NM_AP_SEC_WEP = 2
NM_AP_SEC_WPA = 3
NM_AP_SEC_WPA2 = 4


class CellRendererSecurity(Gtk.CellRendererPixbuf):

    __gtype_name__ = "CellRendererSecurity"
    __gproperties__ = {"security": (GObject.TYPE_UINT,
                                    "Security", "Security",
                                    0, glib.MAXUINT, 0,
                                    GObject.ParamFlags.READWRITE),
                       }

    def __init__(self):
        super().__init__()
        self.security = NM_AP_SEC_UNKNOWN
        self.icon_name = ""

    def do_get_property(self, prop):
        if prop.name == 'security':
            return self.security
        else:
            raise AttributeError('unknown property %s' % prop.name)

    def do_set_property(self, prop, value):
        if prop.name == 'security':
            self.security = value
            self._set_icon_name(value)
        else:
            raise AttributeError('unknown property %s' % prop.name)

    def _set_icon_name(self, security):
        self.icon_name = ""
        if security not in (NM_AP_SEC_NONE, NM_AP_SEC_UNKNOWN):
            self.icon_name = "network-wireless-encrypted-symbolic"

        self.set_property("icon-name", self.icon_name)


class NetworkControlBox(GObject.GObject):

    __gsignals__ = {
        "nm-state-changed": (GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, []),
        "device-state-changed": (GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, [str, int, int, int]),
        "apply-hostname": (GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, []),
    }

    supported_device_types = [
        NM.DeviceType.ETHERNET,
        NM.DeviceType.WIFI,
        NM.DeviceType.TEAM,
        NM.DeviceType.BOND,
        NM.DeviceType.VLAN,
        NM.DeviceType.BRIDGE,
    ]

    virtual_device_types = [
        NM.DeviceType.TEAM,
        NM.DeviceType.BOND,
        NM.DeviceType.VLAN,
        NM.DeviceType.BRIDGE,
    ]

    wired_ui_device_types = [
        NM.DeviceType.ETHERNET,
        NM.DeviceType.TEAM,
        NM.DeviceType.BOND,
        NM.DeviceType.VLAN,
        NM.DeviceType.BRIDGE,
    ]

    device_type_sort_value = {
        NM.DeviceType.ETHERNET : "1",
        NM.DeviceType.WIFI : "2",
    }

    device_type_name = {
        NM.DeviceType.UNKNOWN: N_("Unknown"),
        NM.DeviceType.ETHERNET: N_("Ethernet"),
        NM.DeviceType.WIFI: N_("Wireless"),
        NM.DeviceType.BOND: N_("Bond"),
        NM.DeviceType.VLAN: N_("VLAN"),
        NM.DeviceType.TEAM: N_("Team"),
        NM.DeviceType.BRIDGE: N_("Bridge"),
    }

    def __init__(self, builder, client, network_module, spoke=None):

        super().__init__()

        self.builder = builder
        self._running_nmce = None
        self.spoke = spoke
        self.client = client
        self._network_module = network_module

        # button for creating of virtual bond and vlan devices
        self.builder.get_object("add_toolbutton").set_sensitive(True)
        self.builder.get_object("add_toolbutton").connect("clicked",
                                                           self.on_add_device_clicked)
        self.builder.get_object("remove_toolbutton").set_sensitive(False)
        self.builder.get_object("remove_toolbutton").connect("clicked",
                                                           self.on_remove_device_clicked)

        not_supported = ["start_hotspot_button",
                         "stop_hotspot_button",
                         "heading_hotspot_network_name",
                         "heading_hotspot_security_key",
                         "label_hotspot_network_name",
                         "label_hotspot_security_key",
                         "hbox54",
                        ]

        do_not_show_in_refresh = ["heading_wireless_network_name",
                                  "combobox_wireless_network_name"]
        do_not_show_in_refresh += ["%s_%s_%s" % (widget, ty, value)
                                   for widget in ["heading", "label"]
                                   for ty in ["wired", "wireless"]
                                   for value in ["ipv4", "ipv6", "dns", "route"]]
        do_not_show_in_refresh += ["%s_wired_%s" % (widget, value)
                                   for widget in ["heading", "label"]
                                   for value in ["slaves", "vlanid", "parent"]]

        for ident in not_supported + do_not_show_in_refresh:
            self.builder.get_object(ident).set_no_show_all(True)
            self.builder.get_object(ident).hide()

        self.builder.get_object("notebook_types").set_show_tabs(False)

        # to prevent UI update signals races
        self._updating_device = False

        # devices list
        # limited to wired and wireless
        treeview = self.builder.get_object("treeview_devices")
        self._add_device_columns(treeview)
        self.dev_cfg_store = self.builder.get_object("liststore_devices")
        self.dev_cfg_store.set_sort_column_id(2, Gtk.SortType.ASCENDING)
        selection = treeview.get_selection()
        selection.set_mode(Gtk.SelectionMode.BROWSE)
        selection.connect("changed", self.on_device_selection_changed)

        # wireless APs list
        combobox = self.builder.get_object("combobox_wireless_network_name")
        self._add_ap_icons(combobox)
        model = combobox.get_model()
        model.set_sort_column_id(2, Gtk.SortType.ASCENDING)
        combobox.connect("changed", self.on_wireless_ap_changed_cb)
        self.selected_ap = None

        self.builder.get_object("device_wired_off_switch").connect("notify::active",
                                                             self.on_device_off_toggled)
        self.builder.get_object("device_wireless_off_switch").connect("notify::active",
                                                             self.on_device_off_toggled)
        self.builder.get_object("button_wired_options").connect("clicked",
                                                           self.on_edit_connection)
        self.builder.get_object("button_wireless_options").connect("clicked",
                                                              self.on_edit_connection)
        self.entry_hostname = self.builder.get_object("entry_hostname")
        self.label_current_hostname = self.builder.get_object("label_current_hostname")
        self.button_apply_hostname = self.builder.get_object("button_apply_hostname")
        self.button_apply_hostname.connect("clicked", self.on_apply_hostname)

    @property
    def vbox(self):
        return self.builder.get_object("networkControlBox_vbox")

    def _add_ap_icons(self, combobox):
        cell = CellRendererSecurity()
        cell.set_padding(4, 0)
        combobox.pack_start(cell, False)
        combobox.add_attribute(cell, "security", 5)

        cell = CellRendererSignal()
        cell.set_padding(4, 0)
        #cell.set_property("xalign", 1.0)
        combobox.pack_start(cell, False)
        combobox.add_attribute(cell, "signal", 3)

    def _add_device_columns(self, treeview):
        rnd = Gtk.CellRendererPixbuf()
        rnd.set_property("stock-size", Gtk.IconSize.DND)
        # TODO Gtk3 icon-name? (also at other places)
        col = Gtk.TreeViewColumn("Icon", rnd, **{"icon-name":0})
        treeview.append_column(col)

        rnd = Gtk.CellRendererText()
        rnd.set_property("wrap-mode", Pango.WrapMode.WORD)
        col = Gtk.TreeViewColumn("Text", rnd, markup=2)
        col.set_sort_column_id(2)
        col.set_expand(True)
        treeview.append_column(col)

    def initialize(self):
        self.client.connect("notify::%s" % NM.CLIENT_WIRELESS_ENABLED,
                            self.on_wireless_enabled)
        self.client.connect("notify::%s" % NM.CLIENT_STATE,
                            self.on_nm_state_changed)

        self._load_device_configurations()
        self._network_module.DeviceConfigurationChanged.connect(
            self.on_device_configurations_changed
        )

        # select the first device
        treeview = self.builder.get_object("treeview_devices")
        selection = treeview.get_selection()
        itr = self.dev_cfg_store.get_iter_first()
        if itr:
            selection.select_iter(itr)

    def on_device_configurations_changed(self, changes):
        log.debug("device configurations changed: %s", changes)
        self._update_device_configurations(changes)
        self.refresh_ui()

    def _update_device_configurations(self, changes):
        for old_values, new_values in changes:
            old_cfg = NetworkDeviceConfiguration.from_structure(old_values)
            new_cfg = NetworkDeviceConfiguration.from_structure(new_values)

            device_type = old_cfg.device_type or new_cfg.device_type
            # physical devices - devices persist in store
            if device_type not in self.virtual_device_types:
                # device added
                if not old_cfg.device_name and new_cfg.device_name:
                    self.add_dev_cfg(new_cfg)
                    self.watch_dev_cfg_device(new_cfg)
                # device removed
                elif old_cfg.device_name and not new_cfg.device_name:
                    self.remove_dev_cfg(old_cfg)
                # connection modified
                else:
                    self.update_dev_cfg(old_cfg, new_cfg)

            # virtual devices - connections persist in store
            else:
                # connection added
                if not old_cfg.connection_uuid and new_cfg.connection_uuid:
                    self.add_dev_cfg(new_cfg)
                # connection removed
                elif old_cfg.connection_uuid and not new_cfg.connection_uuid:
                    self.remove_dev_cfg(old_cfg)
                # virtual device added or removed
                elif old_cfg.connection_uuid:
                    self.update_dev_cfg(old_cfg, new_cfg)
                    # added
                    if not old_cfg.device_name and new_cfg.device_name:
                        self.watch_dev_cfg_device(new_cfg)

    def _load_device_configurations(self):
        device_configurations = self._network_module.GetDeviceConfigurations()
        self.dev_cfg_store.clear()
        for device_configuration in device_configurations:
            dev_cfg = NetworkDeviceConfiguration.from_structure(device_configuration)
            self.add_dev_cfg(dev_cfg)
            self.watch_dev_cfg_device(dev_cfg)

    def refresh(self):
        self.refresh_ui()

    # Signal handlers.
    def on_nm_state_changed(self, *args):
        self.emit("nm-state-changed")

    def on_device_selection_changed(self, *args):
        self.refresh_ui()

    def on_device_state_changed(self, device, new_state, *args):
        self.emit("device-state-changed", device.get_iface(), new_state, *args)
        if new_state == NM.DeviceState.SECONDARIES:
            return
        self._refresh_carrier_info()
        dev_cfg = self.selected_dev_cfg()
        if dev_cfg and dev_cfg.device_name == device.get_iface():
            self.refresh_ui(state=new_state)

    def on_device_config_changed(self, device, *args):
        dev_cfg = self.selected_dev_cfg()
        if dev_cfg and dev_cfg.device_name == device.get_iface():
            self.refresh_ui()

    def on_wireless_ap_changed_cb(self, combobox, *args):
        if self._updating_device:
            return
        itr = combobox.get_active_iter()
        if not itr:
            return

        dev_cfg = self.selected_dev_cfg()
        if not dev_cfg:
            return

        device = self.client.get_device_by_iface(dev_cfg.device_name)

        ap, ssid_target = combobox.get_model().get(itr, 0, 1)
        self.selected_ap = ap

        log.info("selected access point: %s", ssid_target)

        cons = ap.filter_connections(device.filter_connections(self.client.get_connections()))
        if cons:
            con = cons[0]
            self.client.activate_connection_async(con, device, ap.get_path(), None)
        else:
            if self._ap_is_enterprise(ap):
                # Create a connection for the ap and [Configure] it later with nm-c-e
                con = NM.SimpleConnection.new()
                s_con = NM.SettingConnection.new()
                s_con.set_property('uuid', str(uuid4()))
                s_con.set_property('id', ssid_target)
                s_con.set_property('type', '802-11-wireless')
                s_wireless = NM.SettingWireless.new()
                s_wireless.set_property('ssid', ap.get_ssid())
                s_wireless.set_property('mode', 'infrastructure')
                log.debug("adding connection for WPA-Enterprise AP %s", ssid_target)
                con.add_setting(s_con)
                con.add_setting(s_wireless)
                persistent = True
                self.client.add_connection_async(con, persistent, None)
                self.builder.get_object("button_wireless_options").set_sensitive(True)
            else:
                self.client.add_and_activate_connection_async(None, device, ap.get_path(), None)

    def _find_first_ap_setting(self, device, ap):
        for con in device.filter_connections(self.client.get_connections()):
            wireless_setting = con.get_setting_wireless()
            if not wireless_setting or not wireless_setting.get_ssid():
                # setting is None or non-broadcast AP, we ignore these
                return
            if wireless_setting.get_ssid().get_data() == ap.get_ssid().get_data():
                return con

    def on_edit_connection(self, *args):
        dev_cfg = self.selected_dev_cfg()
        if not dev_cfg:
            return

        device = self.client.get_device_by_iface(dev_cfg.device_name)
        con = self.client.get_connection_by_uuid(dev_cfg.connection_uuid)
        device_type = dev_cfg.device_type
        iface = dev_cfg.device_name
        activate = None
        ssid = ""

        if device_type == NM.DeviceType.WIFI:
            if not self.selected_ap:
                return
            con = self._find_first_ap_setting(device, self.selected_ap)
            if not con:
                log.debug("on_edit_connection: connection for ap %s not found", self.selected_ap)
                return
            ssid = self.selected_ap.get_ssid().get_data()
            # 871132 auto activate wireless connection after editing if it is not
            # already activated (assume entering secrets)
            condition = lambda: self.selected_ap != device.get_active_access_point()
            activate = (con, device, condition)
        else:
            if not con:
                log.debug("on_edit_connection: connection for device %s not found", iface)
                if device_type == NM.DeviceType.ETHERNET:
                    # Create default connection for the device and run nm-c-e on it
                    default_con = self._default_eth_con(iface, autoconnect=False)
                    persistent = False
                    log.info("creating new connection for %s device", iface)
                    self.client.add_connection_async(default_con, persistent, None,
                            self._default_connection_added_cb, activate)
                return

            if device and device.get_state() == NM.DeviceState.ACTIVATED:
                # Reactivate the connection after configuring it (if it changed)
                settings = con.to_dbus(NM.ConnectionSerializationFlags.ALL)
                settings_changed = lambda: settings != con.to_dbus(NM.ConnectionSerializationFlags.ALL)
                activate = (con, device, settings_changed)

        log.info("configuring connection %s device %s ssid %s",
                 con.get_uuid(), iface, ssid)
        self._run_nmce(con.get_uuid(), activate)

    def _default_connection_added_cb(self, client, result, activate):
        con = client.add_connection_finish(result)
        uuid = con.get_setting_connection().get_uuid()
        log.info("configuring new connection %s", uuid)
        self._run_nmce(uuid, activate)

    def _run_nmce(self, uuid, activate):
        self.kill_nmce(msg="Configure button clicked")
        proc = startProgram(["nm-connection-editor", "--keep-above", "--edit", "%s" % uuid], reset_lang=False)
        self._running_nmce = proc

        PidWatcher().watch_process(proc.pid, self.on_nmce_exited, activate)

    def _default_eth_con(self, iface, autoconnect):
        con = NM.SimpleConnection.new()
        s_con = NM.SettingConnection.new()
        s_con.set_property('uuid', str(uuid4()))
        s_con.set_property('id', iface)
        s_con.set_property('interface-name', iface)
        s_con.set_property('autoconnect', autoconnect)
        s_con.set_property('type', '802-3-ethernet')
        s_wired = NM.SettingWired.new()
        con.add_setting(s_con)
        con.add_setting(s_wired)
        return con

    def kill_nmce(self, msg=""):
        if not self._running_nmce:
            return False

        log.debug("killing running nm-c-e %s: %s", self._running_nmce.pid, msg)
        self._running_nmce.kill()
        self._running_nmce = None
        return True

    def on_nmce_exited(self, pid, condition, activate=None):
        # waitpid() has been called, make sure we don't do anything else with the proc
        self._running_nmce = None
        log.debug("nm-c-e exited with status %s", condition)

        # nm-c-e was closed normally, not killed by anaconda
        if condition == 0:
            if activate:
                # The default of None confuses pylint
                con, device, activate_condition = activate # pylint: disable=unpacking-non-sequence
                if activate_condition():
                    gtk_call_once(self._activate_connection_cb, con, device)
            self._network_module.LogConfigurationState("Connection Editor was run.")

    def _activate_connection_cb(self, con, device):
        self.client.activate_connection_async(con, device, None, None)
        if self.spoke:
            self.spoke.networking_changed = True

    def on_wireless_enabled(self, *args):
        switch = self.builder.get_object("device_wireless_off_switch")
        self._updating_device = True
        switch.set_active(self.client.wireless_get_enabled())
        self._updating_device = False

    def on_device_off_toggled(self, switch, *args):
        if self._updating_device:
            return

        active = switch.get_active()
        dev_cfg = self.selected_dev_cfg()
        if not dev_cfg:
            return
        device = self.client.get_device_by_iface(dev_cfg.device_name)
        con = self.client.get_connection_by_uuid(dev_cfg.connection_uuid)
        iface = dev_cfg.device_name

        log.info("device %s switched %s", iface, "on" if active else "off")

        if dev_cfg.device_type == NM.DeviceType.WIFI:
            self.client.wireless_set_enabled(active)
        else:
            if active:
                if not con:
                    log.debug("on_device_off_toggled: no connection for %s", iface)
                    return

                self.client.activate_connection_async(con, device, None, None)
            else:
                if not device:
                    log.debug("on_device_off_toggled: no device for %s", iface)
                    return
                device.disconnect(None)

        if self.spoke:
            self.spoke.networking_changed = True

    def on_add_device_clicked(self, *args):
        dialog = self.builder.get_object("add_device_dialog")
        with self.spoke.main_window.enlightbox(dialog):
            rc = dialog.run()
        dialog.hide()
        if rc == 1:
            ai = self.builder.get_object("combobox_add_device").get_active_iter()
            model = self.builder.get_object("liststore_add_device")
            dev_type = model[ai][1]
            self.add_device(dev_type)

    def on_remove_device_clicked(self, *args):
        selection = self.builder.get_object("treeview_devices").get_selection()
        model, itr = selection.get_selected()
        if not itr:
            return None
        dev_cfg = model[itr][DEVICES_COLUMN_OBJECT]
        con = self.client.get_connection_by_uuid(dev_cfg.connection_uuid)
        if con:
            con.delete()

    def on_apply_hostname(self, *args):
        self.emit("apply-hostname")

    def add_device(self, ty):
        log.info("adding device of type %s", ty)
        self.kill_nmce(msg="Add device button clicked")
        proc = startProgram(["nm-connection-editor", "--keep-above", "--create", "--type=%s" % ty], reset_lang=False)
        self._running_nmce = proc

        PidWatcher().watch_process(proc.pid, self.on_nmce_exited)

    def selected_dev_cfg(self):
        selection = self.builder.get_object("treeview_devices").get_selection()
        model, itr = selection.get_selected()
        if not itr:
            return None
        return model[itr][DEVICES_COLUMN_OBJECT]

    def add_dev_cfg(self, dev_cfg):
        log.debug("adding device configuration: %s", dev_cfg)
        row = [None, None, None, dev_cfg]
        self._update_row_from_object(row)
        self.dev_cfg_store.append(row)

    def _update_row_from_object(self, row):
        dev_cfg = row[DEVICES_COLUMN_OBJECT]
        row[DEVICES_COLUMN_ICON_NAME] = self._dev_icon_name(dev_cfg)
        row[DEVICES_COLUMN_SORT] = self.device_type_sort_value.get(dev_cfg.device_type, "100")
        row[DEVICES_COLUMN_TITLE] = self._dev_title(dev_cfg)

    def watch_dev_cfg_device(self, dev_cfg):
        device = self.client.get_device_by_iface(dev_cfg.device_name)
        if device:
            device.connect("notify::ip4-config", self.on_ip_obj_changed, IPV4_CONFIG)
            device.connect("notify::ip6-config", self.on_ip_obj_changed, IPV6_CONFIG)
            device.connect("state-changed", self.on_device_state_changed)

    def remove_dev_cfg(self, dev_cfg):
        log.debug("removing device configuration: %s", dev_cfg)
        for row in self.dev_cfg_store:
            stored_cfg = row[DEVICES_COLUMN_OBJECT]
            if stored_cfg == dev_cfg:
                self.dev_cfg_store.remove(row.iter)
                return
        log.debug("configuration to be removed not found")

    def update_dev_cfg(self, old_cfg, new_cfg):
        log.debug("updating device configuration: %s -> %s", old_cfg, new_cfg)
        for row in self.dev_cfg_store:
            stored_cfg = row[DEVICES_COLUMN_OBJECT]
            if stored_cfg == old_cfg:
                row[DEVICES_COLUMN_OBJECT] = new_cfg
                self._update_row_from_object(row)
                return
        log.debug("configuration to be updated not found")

    def on_ip_obj_changed(self, device, *args):
        """Callback when ipX-config objects will be changed.

        Register callback on properties (IP address, gateway...) of these ipX-config
        objects when they are created.
        """
        log.debug("%s object changed", args[1])
        self.on_device_config_changed(device)
        if args[1] == IPV4_CONFIG:
            config = device.props.ip4_config
        else:
            config = device.props.ip6_config

        if config:
            # register callback when inner NMIP[4,6]Config object changed
            config.connect("notify::addresses", self.on_config_changed, device)
            config.connect("notify::gateway", self.on_config_changed, device)
            config.connect("notify::nameservers", self.on_config_changed, device)

    def on_config_changed(self, config, *args):
        """Callback on property change of ipX-config objects.

        Call method which show changed properties (IP, gateway...) to an user.
        """
        self.on_device_config_changed(args[1])

    def _dev_icon_name(self, dev_cfg):
        icon_name = ""
        if dev_cfg.device_type in self.wired_ui_device_types:
            device = self.client.get_device_by_iface(dev_cfg.device_name)
            if device:
                if device.get_state() == NM.DeviceState.UNAVAILABLE:
                    icon_name = "network-wired-disconnected"
                else:
                    icon_name = "network-wired"
            else:
                icon_name = "network-wired-disconnected"
        elif dev_cfg.device_type == NM.DeviceType.WIFI:
            icon_name = "network-wireless"

        return icon_name

    def _dev_title(self, dev_cfg):
        unplugged = ''
        device = self.client.get_device_by_iface(dev_cfg.device_name)

        if device:
            if (device.get_state() == NM.DeviceState.UNAVAILABLE
                and device.get_device_type() == NM.DeviceType.ETHERNET
                and not device.get_carrier()):
                # TRANSLATORS: ethernet cable is unplugged
                unplugged = ', <i>%s</i>' % escape_markup(_("unplugged"))
        connection_name = ""
        if dev_cfg.device_type in self.virtual_device_types:
            con = self.client.get_connection_by_uuid(dev_cfg.connection_uuid)
            if con:
                con_id = con.get_setting_connection().get_id()
                if con_id:
                    connection_name = " - {}".format(con_id)
        # pylint: disable=unescaped-markup
        title = '<span size="large">%s%s (%s%s)</span>' % \
                 (escape_markup(_(self.device_type_name.get(dev_cfg.device_type, ""))),
                  escape_markup(connection_name),
                  escape_markup(dev_cfg.device_name),
                  unplugged)

        if device:
            title += '\n<span size="small">%s %s</span>' % \
                    (escape_markup(device.get_vendor() or ""),
                     escape_markup(device.get_product() or ""))
        return title

    def refresh_ui(self, state=None):

        dev_cfg = self.selected_dev_cfg()
        if not dev_cfg:
            # the list is empty (no supported devices)
            notebook = self.builder.get_object("notebook_types")
            notebook.set_current_page(5)
            return

        self._refresh_device_type_page(dev_cfg.device_type)
        self._refresh_header_ui(dev_cfg, state)
        self._refresh_slaves(dev_cfg)
        self._refresh_parent_vlanid(dev_cfg)
        self._refresh_speed_hwaddr(dev_cfg, state)
        self._refresh_ap(dev_cfg, state)
        self._refresh_device_cfg(dev_cfg)

    def _refresh_device_cfg(self, dev_cfg):

        if dev_cfg.device_type in self.wired_ui_device_types:
            dt = "wired"
        elif dev_cfg.device_type  == NM.DeviceType.WIFI:
            dt = "wireless"
        else:
            return

        device = self.client.get_device_by_iface(dev_cfg.device_name)
        if device:
            ipv4cfg = device.get_ip4_config()
            ipv6cfg = device.get_ip6_config()
        else:
            ipv4cfg = ipv6cfg = None

        if ipv4cfg:
            addr_str = " ".join("%s/%d" % (a.get_address(), a.get_prefix())
                                           for a in ipv4cfg.get_addresses())
            gateway_str = ipv4cfg.get_gateway()
            dnss_str = " ".join(ipv4cfg.get_nameservers())
        else:
            addr_str = dnss_str = gateway_str = None
        self._set_device_info_value(dt, "ipv4", addr_str)
        self._set_device_info_value(dt, "dns", dnss_str)
        self._set_device_info_value(dt, "route", gateway_str)

        addr6_str = ""
        if ipv6cfg:
            addr6_str = " ".join("%s/%d" % (a.get_address(), a.get_prefix())
                                            for a in ipv6cfg.get_addresses()
                                            # Do not display link-local addresses
                                            if not a.get_address().startswith("fe80:"))
        self._set_device_info_value(dt, "ipv6", addr6_str.strip() or None)

        if ipv4cfg and addr6_str:
            self.builder.get_object("heading_%s_ipv4" % dt).set_label(_("IPv4 Address"))
            self.builder.get_object("heading_%s_ipv6" % dt).set_label(_("IPv6 Address"))
        elif ipv4cfg:
            self.builder.get_object("heading_%s_ipv4" % dt).set_label(_("IP Address"))
        elif addr6_str:
            self.builder.get_object("heading_%s_ipv6" % dt).set_label(_("IP Address"))

        return False

    def _refresh_ap(self, dev_cfg, state=None):
        if dev_cfg.device_type != NM.DeviceType.WIFI:
            return

        device = self.client.get_device_by_iface(dev_cfg.device_name)
        if state is None:
            state = device.get_state()
        if state == NM.DeviceState.UNAVAILABLE:
            ap_str = None
        else:
            active_ap = device.get_active_access_point()
            if active_ap:
                ap_str = self._ap_security_string(active_ap)
            else:
                ap_str = ""

        self._set_device_info_value("wireless", "security", ap_str)

        if state == NM.DeviceState.UNAVAILABLE:
            self.builder.get_object("heading_wireless_network_name").hide()
            self.builder.get_object("combobox_wireless_network_name").hide()
        else:
            self.builder.get_object("heading_wireless_network_name").show()
            self.builder.get_object("combobox_wireless_network_name").show()

            store = self.builder.get_object("liststore_wireless_network")
            self._updating_device = True
            store.clear()
            aps = self._get_strongest_unique_aps(device.get_access_points())
            for ap in aps:
                self._add_ap(ap, active_ap == ap)
            # TODO: add access point other...
            if active_ap:
                combobox = self.builder.get_object("combobox_wireless_network_name")
                for i in combobox.get_model():
                    if i[0] == active_ap:
                        combobox.set_active_iter(i.iter)
                        self.selected_ap = active_ap
                        break
            self._updating_device = False

    def _refresh_slaves(self, dev_cfg):
        if dev_cfg.device_type in [NM.DeviceType.BOND,
                                   NM.DeviceType.TEAM,
                                   NM.DeviceType.BRIDGE]:
            slaves = ""
            device = self.client.get_device_by_iface(dev_cfg.device_name)
            if device:
                slaves = ",".join(s.get_iface() for s in device.get_slaves())
            self._set_device_info_value("wired", "slaves", slaves)

    def _refresh_parent_vlanid(self, dev_cfg):
        if dev_cfg.device_type == NM.DeviceType.VLAN:
            parent = ""
            vlanid = ""
            device = self.client.get_device_by_iface(dev_cfg.device_name)
            if device:
                vlanid = device.get_vlan_id()
                parent = device.get_parent().get_iface()
            else:
                con = self.client.get_connection_by_uuid(dev_cfg.connection_uuid)
                if con:
                    vlanid = con.get_setting_vlan().get_id()
                    parent = con.get_setting_vlan().get_parent()
            self._set_device_info_value("wired", "vlanid", str(vlanid))
            self._set_device_info_value("wired", "parent", parent)

    def _refresh_speed_hwaddr(self, dev_cfg, state=None):
        dev_type = dev_cfg.device_type
        if dev_type in self.wired_ui_device_types:
            dt = "wired"
        elif dev_type == NM.DeviceType.WIFI:
            dt = "wireless"
        else:
            return

        device = self.client.get_device_by_iface(dev_cfg.device_name)

        # Speed
        speed = None
        if device:
            if dev_type == NM.DeviceType.ETHERNET:
                speed = device.get_speed()
            elif dev_type == NM.DeviceType.WIFI:
                speed = device.get_bitrate() / 1000

        if state is None and device:
            state = device.get_state()

        if not device or state == NM.DeviceState.UNAVAILABLE:
            speed_str = None
        elif speed:
            speed_str = _("%d Mb/s") % speed
        else:
            speed_str = ""
        self._set_device_info_value(dt, "speed", speed_str)

        # Hardware address
        hwaddr = device and device.get_hw_address()
        self._set_device_info_value(dt, "mac", hwaddr)

    def _refresh_device_type_page(self, dev_type):
        notebook = self.builder.get_object("notebook_types")
        if dev_type == NM.DeviceType.ETHERNET:
            notebook.set_current_page(0)
            self.builder.get_object("heading_wired_slaves").hide()
            self.builder.get_object("label_wired_slaves").hide()
            self.builder.get_object("heading_wired_vlanid").hide()
            self.builder.get_object("label_wired_vlanid").hide()
            self.builder.get_object("heading_wired_parent").hide()
            self.builder.get_object("label_wired_parent").hide()
            self.builder.get_object("remove_toolbutton").set_sensitive(False)
        elif dev_type in [NM.DeviceType.BOND,
                          NM.DeviceType.TEAM,
                          NM.DeviceType.BRIDGE]:
            notebook.set_current_page(0)
            self.builder.get_object("heading_wired_slaves").show()
            self.builder.get_object("label_wired_slaves").show()
            self.builder.get_object("heading_wired_vlanid").hide()
            self.builder.get_object("label_wired_vlanid").hide()
            self.builder.get_object("heading_wired_parent").hide()
            self.builder.get_object("label_wired_parent").hide()
            self.builder.get_object("remove_toolbutton").set_sensitive(True)
        elif dev_type == NM.DeviceType.VLAN:
            notebook.set_current_page(0)
            self.builder.get_object("heading_wired_slaves").hide()
            self.builder.get_object("label_wired_slaves").hide()
            self.builder.get_object("heading_wired_vlanid").show()
            self.builder.get_object("label_wired_vlanid").show()
            self.builder.get_object("heading_wired_parent").show()
            self.builder.get_object("label_wired_parent").show()
            self.builder.get_object("remove_toolbutton").set_sensitive(True)
        elif dev_type == NM.DeviceType.WIFI:
            notebook.set_current_page(1)
            self.builder.get_object("button_wireless_options").set_sensitive(self.selected_ap is not None)

    def _refresh_carrier_info(self):
        for row in self.dev_cfg_store:
            row[DEVICES_COLUMN_TITLE] = self._dev_title(row[DEVICES_COLUMN_OBJECT])

    def _refresh_header_ui(self, dev_cfg, state=None):
        if dev_cfg.device_type in self.wired_ui_device_types:
            dev_type_str = "wired"
        elif dev_cfg.device_type == NM.DeviceType.WIFI:
            dev_type_str = "wireless"
        else:
            return

        if dev_type_str == "wired":
            # update icon according to device status
            img = self.builder.get_object("image_wired_device")
            img.set_from_icon_name(self._dev_icon_name(dev_cfg), Gtk.IconSize.DIALOG)

        # TODO: is this necessary? Isn't it static from glade?
        device_type_label = _(self.device_type_name.get(dev_cfg.device_type, ""))
        self.builder.get_object("label_%s_device" % dev_type_str).set_label(
            "%s (%s)" % (device_type_label, dev_cfg.device_name))

        device = self.client.get_device_by_iface(dev_cfg.device_name)
        if state is None:
            if not device:
                state = NM.DeviceState.DISCONNECTED
            else:
                state = device.get_state()

        self.builder.get_object("label_%s_status" % dev_type_str).set_label(
            localized_string_of_device_state(device, state))

        switch = self.builder.get_object("device_%s_off_switch" % dev_type_str)
        if dev_type_str == "wired":
            visible = state not in (NM.DeviceState.UNAVAILABLE, NM.DeviceState.UNMANAGED)
            switch.set_visible(visible)
            switch.set_no_show_all(not visible)
            self._updating_device = True
            switch.set_active(state not in (NM.DeviceState.UNMANAGED,
                                            NM.DeviceState.UNAVAILABLE,
                                            NM.DeviceState.DISCONNECTED,
                                            NM.DeviceState.DEACTIVATING,
                                            NM.DeviceState.FAILED))
            self._updating_device = False
        elif dev_type_str == "wireless":
            self.on_wireless_enabled()

    def _set_device_info_value(self, dev_type_str, info, value_str):
        heading = self.builder.get_object("heading_%s_%s" % (dev_type_str, info))
        value_label = self.builder.get_object("label_%s_%s" % (dev_type_str, info))
        if value_str is None:
            really_hide(heading)
            really_hide(value_label)
        else:
            really_show(heading)
            really_show(value_label)
            value_label.set_label(value_str)

    def _add_ap(self, ap, active=False):
        ssid = ap.get_ssid()
        if not ssid:
            # get_ssid can return None if AP does not broadcast.
            return
        ssid = ssid.get_data()
        if not ssid:
            return

        mode = ap.get_mode()
        if not mode:
            return

        security = self._ap_security(ap)

        store = self.builder.get_object("liststore_wireless_network")

        # Decode the SSID (a byte sequence) into something resembling a string
        ssid_str = NM.utils_ssid_to_utf8(ssid)

        # the third column is for sorting
        itr = store.append([ap,
                            ssid_str,
                            ssid_str,
                            ap.get_strength(),
                            mode,
                            security])
        if active:
            self.builder.get_object("combobox_wireless_network_name").set_active_iter(itr)

    def _get_strongest_unique_aps(self, access_points):
        strongest_aps = {}
        for ap in access_points:
            if not ap.get_ssid():
                # non-broadcasting AP. We don't do anything with these
                continue
            ssid = ap.get_ssid().get_data()
            if ssid in strongest_aps:
                if ap.get_strength() > strongest_aps[ssid].get_strength():
                    strongest_aps[ssid] = ap
            else:
                strongest_aps[ssid] = ap

        return strongest_aps.values()

    def _ap_security(self, ap):
        ty = NM_AP_SEC_UNKNOWN

        flags = ap.get_flags()
        wpa_flags = ap.get_wpa_flags()
        rsn_flags = ap.get_rsn_flags()

        if (not (flags & NM._80211ApFlags.PRIVACY) and
            wpa_flags == NM._80211ApSecurityFlags.NONE and
            rsn_flags == NM._80211ApSecurityFlags.NONE):
            ty = NM_AP_SEC_NONE
        elif (flags & NM._80211ApFlags.PRIVACY and
              wpa_flags == NM._80211ApSecurityFlags.NONE and
              rsn_flags == NM._80211ApSecurityFlags.NONE):
            ty = NM_AP_SEC_WEP
        elif (not (flags & NM._80211ApFlags.PRIVACY) and
              wpa_flags != NM._80211ApSecurityFlags.NONE and
              rsn_flags != NM._80211ApSecurityFlags.NONE):
            ty = NM_AP_SEC_WPA
        else:
            ty = NM_AP_SEC_WPA2

        return ty

    def _ap_security_string(self, ap):

        flags = ap.get_flags()
        wpa_flags = ap.get_wpa_flags()
        rsn_flags = ap.get_rsn_flags()

        sec_str = ""

        if ((flags & NM._80211ApFlags.PRIVACY) and
            wpa_flags == NM._80211ApSecurityFlags.NONE and
            rsn_flags == NM._80211ApSecurityFlags.NONE):
            sec_str += "%s, " % _("WEP")

        if wpa_flags != NM._80211ApSecurityFlags.NONE:
            sec_str += "%s, " % _("WPA")

        if rsn_flags != NM._80211ApSecurityFlags.NONE:
            sec_str += "%s, " % _("WPA2")

        if ((wpa_flags & NM._80211ApSecurityFlags.KEY_MGMT_802_1X) or
            (rsn_flags & NM._80211ApSecurityFlags.KEY_MGMT_802_1X)):
            sec_str += "%s, " % _("Enterprise")

        if sec_str:
            sec_str = sec_str[:-2]
        else:
            sec_str = _("None")

        return sec_str

    def _ap_is_enterprise(self, ap):
        wpa_flags = ap.get_wpa_flags()
        rsn_flags = ap.get_rsn_flags()
        return ((wpa_flags & NM._80211ApSecurityFlags.KEY_MGMT_802_1X) or
                (rsn_flags & NM._80211ApSecurityFlags.KEY_MGMT_802_1X))

    @property
    def hostname(self):
        return self.entry_hostname.get_text()

    @hostname.setter
    def hostname(self, value):
        if not value:
            return
        self.entry_hostname.set_text(value)

    @property
    def current_hostname(self):
        return self.label_current_hostname.get_text()

    @current_hostname.setter
    def current_hostname(self, value):
        if not value:
            return
        self.label_current_hostname.set_text(value)

    def disconnect_client_callbacks(self):
        for cb in [self.on_wireless_enabled, self.on_nm_state_changed]:
            _try_disconnect(self.client, cb)

        for device in self.client.get_devices():
            _try_disconnect(device, self.on_device_config_changed)
            _try_disconnect(device, self.on_device_state_changed)
            _try_disconnect(device, self.on_ip_obj_changed)
            for config in self._get_ip_configs(device):
                _try_disconnect(config, self.on_config_changed)

        self._network_module.DeviceConfigurationChanged.disconnect(
            self.on_device_configurations_changed
        )

    def _get_ip_configs(self, device):
        out = []
        try:
            out.append(self.props.ip4_config)
        except AttributeError:
            pass
        try:
            out.append(self.props.ip6_config)
        except AttributeError:
            pass

        return out


def _try_disconnect(obj, callback):
    try:
        obj.disconnect_by_func(callback)
    except TypeError as e:
        if "nothing connected" not in str(e):
            log.debug("%s", e)


class SecretAgentDialog(GUIObject):
    builderObjects = ["secret_agent_dialog"]
    mainWidgetName = "secret_agent_dialog"
    uiFile = "spokes/network.glade"

    def __init__(self, *args, **kwargs):
        self._content = kwargs.pop('content', {})
        super().__init__(*args, **kwargs)
        self.builder.get_object("label_message").set_text(self._content['message'])
        self._connect_button = self.builder.get_object("connect_button")

    def initialize(self):
        self._entries = {}
        grid = Gtk.Grid()
        grid.set_row_spacing(6)
        grid.set_column_spacing(6)

        for row, secret in enumerate(self._content['secrets']):
            label = Gtk.Label(label=secret['label'], halign=Gtk.Align.START)
            entry = Gtk.Entry(hexpand=True)
            entry.set_text(secret['value'])
            if secret['key']:
                self._entries[secret['key']] = entry
            else:
                entry.set_sensitive(False)
            if secret['password']:
                entry.set_visibility(False)
            self._validate(entry, secret)
            entry.connect("changed", self._validate, secret)
            entry.connect("activate", self._password_entered_cb)
            label.set_use_underline(True)
            label.set_mnemonic_widget(entry)
            grid.attach(label, 0, row, 1, 1)
            grid.attach(entry, 1, row, 1, 1)

        self.builder.get_object("password_box").add(grid)

    def run(self):
        self.initialize()
        self.window.show_all()
        rc = self.window.run()
        for secret in self._content['secrets']:
            if secret['key']:
                secret['value'] = self._entries[secret['key']].get_text()
        self.window.destroy()
        return rc

    @property
    def valid(self):
        return all(secret.get('valid', False) for secret in self._content['secrets'])

    def _validate(self, entry, secret):
        secret['value'] = entry.get_text()
        if secret['validate']:
            secret['valid'] = secret['validate'](secret)
        else:
            secret['valid'] = len(secret['value']) > 0
        self._update_connect_button()

    def _password_entered_cb(self, entry):
        if self._connect_button.get_sensitive() and self.valid:
            self.window.response(1)

    def _update_connect_button(self):
        self._connect_button.set_sensitive(self.valid)


secret_agent = None


class NotAuthorizedException(dbus.DBusException):
    _dbus_error_name = SECRET_AGENT_IFACE + '.NotAuthorized'


class SecretAgent(dbus.service.Object):
    def __init__(self, spoke):
        self._bus = dbus.SystemBus()
        self.spoke = spoke
        super().__init__(self._bus, "/org/freedesktop/NetworkManager/SecretAgent")

    @dbus.service.method(SECRET_AGENT_IFACE,
                         in_signature='a{sa{sv}}osasb',
                         out_signature='a{sa{sv}}',
                         sender_keyword='sender')
    def GetSecrets(self, connection_hash, connection_path, setting_name, hints, flags, sender=None):
        if not sender:
            raise NotAuthorizedException("Internal error: couldn't get sender")
        uid = self._bus.get_unix_user(sender)
        if uid != 0:
            raise NotAuthorizedException("UID %d not authorized" % uid)

        log.debug("secrets requested path '%s' setting '%s' hints '%s' new %d",
                  connection_path, setting_name, str(hints), flags)
        if not (flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION):
            return

        content = self._get_content(setting_name, connection_hash)
        dialog = SecretAgentDialog(self.spoke.data, content=content)
        with self.spoke.main_window.enlightbox(dialog.window):
            rc = dialog.run()

        secrets = dbus.Dictionary()
        if rc == 1:
            for secret in content['secrets']:
                if secret['key']:
                    secrets[secret['key']] = secret['value']

        settings = dbus.Dictionary({setting_name: secrets})

        return settings

    def _get_content(self, setting_name, connection_hash):
        content = {}
        connection_type = connection_hash['connection']['type']
        if connection_type == "802-11-wireless":
            content['title'] = _("Authentication required by wireless network")
            content['message'] = _("Passwords or encryption keys are required to access\n"
                                   "the wireless network '%(network_id)s'.") \
                                   % {'network_id':str(connection_hash['connection']['id'])}
            content['secrets'] = self._get_wireless_secrets(setting_name, connection_hash)
        else:
            log.info("Connection type %s not supported by secret agent", connection_type)

        return content

    def _get_wireless_secrets(self, setting_name, connection_hash):
        key_mgmt = connection_hash['802-11-wireless-security']['key-mgmt']
        original_secrets = connection_hash[setting_name]
        secrets = []
        if key_mgmt in ['wpa-none', 'wpa-psk']:
            secrets.append({'label'     : C_('GUI|Network|Secrets Dialog', '_Password:'),
                            'key'      : 'psk',
                            'value'    : original_secrets.get('psk', ''),
                            'validate' : self._validate_wpapsk,
                            'password' : True})
        # static WEP
        elif key_mgmt == 'none':
            key_idx = str(original_secrets.get('wep_tx_keyidx', '0'))
            secrets.append({'label'     : C_('GUI|Network|Secrets Dialog', '_Key:'),
                            'key'      : 'wep-key%s' % key_idx,
                            'value'    : original_secrets.get('wep-key%s' % key_idx, ''),
                            'wep_key_type': original_secrets.get('wep-key-type', ''),
                            'validate' : self._validate_staticwep,
                            'password' : True})
        # WPA-Enterprise
        elif key_mgmt == 'wpa-eap':
            eap = original_secrets['eap'][0]
            if eap in ('md5', 'leap', 'ttls', 'peap'):
                secrets.append({'label'    : _('User name: '),
                                'key'      : None,
                                'value'    : original_secrets.get('identity', ''),
                                'validate' : None,
                                'password' : False})
                secrets.append({'label'    : _('Password: '),
                                'key'      : 'password',
                                'value'    : original_secrets.get('password', ''),
                                'validate' : None,
                                'password' : True})
            elif eap == 'tls':
                secrets.append({'label'    : _('Identity: '),
                                'key'      : None,
                                'value'    : original_secrets.get('identity', ''),
                                'validate' : None,
                                'password' : False})
                secrets.append({'label'    : _('Private key password: '),
                                'key'      : 'private-key-password',
                                'value'    : original_secrets.get('private-key-password', ''),
                                'validate' : None,
                                'password' : True})
        else:
            log.info("Unsupported wireless key management: %s", key_mgmt)

        return secrets

    def _validate_wpapsk(self, secret):
        value = secret['value']
        if len(value) == 64:
            # must be composed of hexadecimal digits only
            return all(c in string.hexdigits for c in value)
        else:
            return 8 <= len(value) <= 63

    def _validate_staticwep(self, secret):
        value = secret['value']
        if secret['wep_key_type'] == NM.WepKeyType.KEY:
            if len(value) in (10, 26):
                return all(c in string.hexdigits for c in value)
            elif len(value) in (5, 13):
                return all(c in string.ascii_letters for c in value)
            else:
                return False
        elif secret['wep_key_type'] == NM.WepKeyType.PASSPHRASE:
            return 0 <= len(value) <= 64
        else:
            return True


def register_secret_agent(spoke):

    if not conf.system.can_configure_network:
        return False

    global secret_agent
    if not secret_agent:
        # Ignore an error from pylint incorrectly analyzing types in dbus-python
        secret_agent = SecretAgent(spoke) # pylint: disable=no-value-for-parameter
        bus = dbus.SystemBus()
        proxy = bus.get_object(NM_SERVICE, AGENT_MANAGER_PATH)
        proxy.Register("anaconda", dbus_interface=AGENT_MANAGER_IFACE)
    else:
        secret_agent.spoke = spoke

    return True


class NetworkSpoke(FirstbootSpokeMixIn, NormalSpoke):
    """
       .. inheritance-diagram:: NetworkSpoke
          :parts: 3
    """
    builderObjects = ["networkWindow", "liststore_wireless_network", "liststore_devices", "add_device_dialog", "liststore_add_device"]
    mainWidgetName = "networkWindow"
    uiFile = "spokes/network.glade"
    help_id = "NetworkSpoke"

    title = CN_("GUI|Spoke", "_Network & Host Name")
    icon = "network-transmit-receive-symbolic"

    category = SystemCategory

    def __init__(self, *args, **kwargs):
        NormalSpoke.__init__(self, *args, **kwargs)
        self.networking_changed = False
        self._network_module = NETWORK.get_proxy()
        self._nm_client = network.get_nm_client()
        self.network_control_box = NetworkControlBox(self.builder, self._nm_client, self._network_module, spoke=self)
        self.network_control_box.hostname = self._network_module.Hostname
        self.network_control_box.current_hostname = self._network_module.GetCurrentHostname()
        self._network_module.CurrentHostnameChanged.connect(self._hostname_changed)
        self.network_control_box.connect("nm-state-changed",
                                         self.on_nm_state_changed)
        self.network_control_box.connect("device-state-changed",
                                         self.on_device_state_changed)
        self.network_control_box.connect("apply-hostname",
                                         self.on_apply_hostname)

    def _hostname_changed(self, hostname):
        gtk_call_once(self._update_hostname)

    def apply(self):
        # Inform network module that device configurations might have been changed
        # and we want to generate kickstart from device configurations
        # (persistent NM / ifcfg configuration), instead of using original kickstart.
        self._network_module.NetworkDeviceConfigurationChanged()
        self._network_module.SetHostname(self.network_control_box.hostname)

        # if installation media or hdd aren't used and settings have changed
        # try if source is available
        if self.networking_changed:
            if self.payload and self.payload.needs_network:
                if ANACONDA_ENVIRON in anaconda_flags.environs:
                    log.debug("network spoke (apply), network configuration changed - restarting payload thread")
                    from pyanaconda.payload.manager import payloadMgr
                    payloadMgr.restart_thread(self.payload, fallback=not anaconda_flags.automatedInstall, onlyOnChange=True)
                else:
                    log.debug("network spoke (apply), network configuration changed - "
                              "skipping restart of payload thread, outside of Anaconda environment")
            else:
                log.debug("network spoke (apply), network configuration changed - "
                          "skipping restart of payload thread, payload does not need network")
        self.networking_changed = False

        self.network_control_box.kill_nmce(msg="leaving network spoke")

    @property
    def completed(self):
        # TODO: check also if source requires updates when implemented
        # If we can't configure network, don't require it
        return (not conf.system.can_configure_network
                or self._network_module.GetActivatedInterfaces())

    @property
    def mandatory(self):
        # the network spoke should be mandatory only if it is running
        # during the installation and if the installation source requires network
        return ANACONDA_ENVIRON in anaconda_flags.environs and self.payload.needs_network

    @property
    def status(self):
        """ A short string describing which devices are connected. """
        return network.status_message(self._nm_client)

    def initialize(self):
        register_secret_agent(self)
        NormalSpoke.initialize(self)
        self.initialize_start()
        self.network_control_box.initialize()
        if not conf.system.can_configure_network:
            self.builder.get_object("network_config_vbox").set_no_show_all(True)
            self.builder.get_object("network_config_vbox").hide()
        else:
            self.builder.get_object("live_hint_label").set_no_show_all(True)
            self.builder.get_object("live_hint_label").hide()

        # report that we are done
        self.initialize_done()

    def refresh(self):
        NormalSpoke.refresh(self)
        self.network_control_box.refresh()
        self.network_control_box.current_hostname = self._network_module.GetCurrentHostname()

    def on_nm_state_changed(self, *args):
        gtk_call_once(self._update_status)
        # TODO MOD replace and test - will NM updating hostname from dhcp being
        # estabilished be propagated to module via hostnamed?
        gtk_call_once(self._update_hostname)

    def on_device_state_changed(self, source, device, new_state, *args):
        if new_state in (NM.DeviceState.ACTIVATED,
                         NM.DeviceState.DISCONNECTED,
                         NM.DeviceState.UNAVAILABLE):
            gtk_call_once(self._update_status)

    def on_apply_hostname(self, *args):
        hostname = self.network_control_box.hostname
        (valid, error) = network.is_valid_hostname(hostname, local=True)
        if not valid:
            self.clear_info()
            msg = _("Host name is not valid: %s") % error
            self.set_warning(msg)
            self.network_control_box.entry_hostname.grab_focus()
        else:
            self.clear_info()
            if conf.system.can_change_hostname:
                self._network_module.SetCurrentHostname(hostname)

    def _update_status(self):
        hubQ.send_message(self.__class__.__name__, self.status)

    def _update_hostname(self):
        self.network_control_box.current_hostname = self._network_module.GetCurrentHostname()

    def on_back_clicked(self, button):
        hostname = self.network_control_box.hostname
        (valid, error) = network.is_valid_hostname(hostname, local=True)
        if not valid:
            self.clear_info()
            msg = _("Host name is not valid: %s") % error
            self.set_warning(msg)
            self.network_control_box.entry_hostname.grab_focus()
        else:
            self.clear_info()
            NormalSpoke.on_back_clicked(self, button)

    def finished(self):
        """Disconnect callbacks

        Called when leaving summary hub
        """
        self.network_control_box.kill_nmce(msg="finished with network spoke")
        self.network_control_box.disconnect_client_callbacks()


class NetworkStandaloneSpoke(StandaloneSpoke):
    """
       .. inheritance-diagram:: NetworkStandaloneSpoke
          :parts: 3
    """
    builderObjects = ["networkStandaloneWindow", "networkControlBox_vbox", "liststore_wireless_network", "liststore_devices", "add_device_dialog", "liststore_add_device"]
    mainWidgetName = "networkStandaloneWindow"
    uiFile = "spokes/network.glade"

    preForHub = SummaryHub
    priority = 10

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._network_module = NETWORK.get_proxy()
        self._nm_client = network.get_nm_client()
        self.network_control_box = NetworkControlBox(self.builder, self._nm_client, self._network_module, spoke=self)

        self.network_control_box.hostname = self._network_module.Hostname
        self.network_control_box.current_hostname = self._network_module.GetCurrentHostname()
        self._network_module.CurrentHostnameChanged.connect(self._hostname_changed)

        parent = self.builder.get_object("AnacondaStandaloneWindow-action_area5")
        parent.add(self.network_control_box.vbox)

        self.network_control_box.connect("nm-state-changed",
                                         self.on_nm_state_changed)
        self.network_control_box.connect("apply-hostname",
                                         self.on_apply_hostname)

        self._initially_available = self.completed
        log.debug("network standalone spoke (init): completed: %s", self._initially_available)
        self._now_available = False

    def _hostname_changed(self, hostname):
        gtk_call_once(self._update_hostname)

    def apply(self):
        # Inform network module that device configurations might have been changed
        # and we want to generate kickstart from device configurations
        # (persistent NM / ifcfg configuration), instead of using original kickstart.
        self._network_module.NetworkDeviceConfigurationChanged()
        self._network_module.SetHostname(self.network_control_box.hostname)

        self._now_available = self.completed

        log.debug("network standalone spoke (apply) payload: %s completed: %s",
                  self.payload.is_ready(), self._now_available)

        if (not self.payload.is_ready() and not self._initially_available
            and self._now_available and self.payload.needs_network):
            from pyanaconda.payload.manager import payloadMgr
            payloadMgr.restart_thread(self.payload, fallback=not anaconda_flags.automatedInstall)

        self.network_control_box.kill_nmce(msg="leaving standalone network spoke")
        self.network_control_box.disconnect_client_callbacks()

    @property
    def completed(self):
        return (not conf.system.can_configure_network
                or self._network_module.GetActivatedInterfaces()
                or not (self.payload.source_type != conf.payload.default_source
                        and self.payload.needs_network))

    def initialize(self):
        register_secret_agent(self)
        super().initialize()
        self.network_control_box.initialize()

    def refresh(self):
        super().refresh()
        self.network_control_box.refresh()
        self.network_control_box.current_hostname = self._network_module.GetCurrentHostname()

    def _on_continue_clicked(self, window, user_data=None):
        hostname = self.network_control_box.hostname
        (valid, error) = network.is_valid_hostname(hostname, local=True)
        if not valid:
            self.clear_info()
            msg = _("Host name is not valid: %s") % error
            self.set_warning(msg)
            self.network_control_box.entry_hostname.grab_focus()
        else:
            self.clear_info()
            StandaloneSpoke._on_continue_clicked(self, window, user_data)

    # Use case: slow dhcp has connected when on spoke
    def on_nm_state_changed(self, *args):
        # TODO MOD replace and test - will NM updating hostname from dhcp being
        # estabilished be propagated to module via hostnamed?
        gtk_call_once(self._update_hostname)

    def on_apply_hostname(self, *args):
        hostname = self.network_control_box.hostname
        (valid, error) = network.is_valid_hostname(hostname, local=True)
        if not valid:
            self.clear_info()
            msg = _("Host name is not valid: %s") % error
            self.set_warning(msg)
            self.network_control_box.entry_hostname.grab_focus()
        else:
            self.clear_info()
            if conf.system.can_change_hostname:
                self._network_module.SetCurrentHostname(hostname)

    def _update_hostname(self):
        self.network_control_box.current_hostname = self._network_module.GetCurrentHostname()

Youez - 2016 - github.com/yon3zu
LinuXploit