text:
<resources xmlns:android="http://schemas.android.com/apk/res/android">

    <style name="Widget" />

    <style name="Widget.ProgressBar">
        <item name="android:indeterminateDrawable">@drawable/progress_medium_holo</item>
    </style>

    <style name="TitleStyle" parent="@style/TextAppearance.AppCompat.Widget.ActionBar.Title">
        <item name="android:textColor">@color/white</item>
    </style>

    <style name="SubTitle" parent="@style/TextAppearance.AppCompat.Widget.ActionBar.Subtitle">
        <item name="android:textColor">@color/white</item>
    </style>

    <style name="OverflowButton" parent="@style/Widget.AppCompat.ActionButton.Overflow">
        <item name="android:src">@mipmap/actionbar_more_icon_normal</item>
    </style>

    <style name="PopupMenu.ListPopupWindow" parent="@style/Widget.AppCompat.Light.ListPopupWindow">
        <!--<item name="android:popupBackground">@color/menu_dropdown_panel_dark</item>-->
        <item name="android:textStyle">bold</item>
    </style>

    <style name="ActionBarBaseStyle" parent="@style/Widget.AppCompat.Light.ActionBar">
        <item name="background">@color/actionbar_background</item>
        <item name="titleTextStyle">@style/TitleStyle</item>
        <item name="android:icon">@android:color/transparent</item>
        <item name="subtitleTextStyle">@style/SubTitle</item>
    </style>

    <style name="ActionBarBaseStyle.Transparent" parent="@style/ActionBarBaseStyle">
        <item name="android:background">@color/transparent</item>
        <item name="background">@color/transparent</item>
    </style>

    <style name="ActionBarBaseTheme" parent="@style/Theme.AppCompat.Light">
        <item name="android:windowBackground">@color/window_background</item>
        <item name="android:popupMenuStyle">@style/PopupMenu.ListPopupWindow</item>
        <item name="actionBarStyle">@style/ActionBarBaseStyle</item>
        <item name="actionOverflowButtonStyle">@style/OverflowButton</item>
        <item name="actionBarItemBackground">@drawable/socialize_titlebar_item_background_selector
        </item>
        <item name="android:actionMenuTextColor">@color/white</item>
        <item name="android:dropDownListViewStyle">@style/SpinnerDropDownListView</item>
        <item name="popupMenuStyle">@style/mylistPopupWindowStyle</item>
    </style>

    <style name="ActionBarBaseTheme.Preview" parent="@style/ActionBarBaseTheme">
        <item name="android:windowBackground">@android:color/black</item>
        <item name="actionBarStyle">@style/ActionBarBaseStyle.Transparent</item>
        <item name="windowActionBarOverlay">true</item>
    </style>

    <style name="ThemePhotoBrowse" parent="@style/Theme.AppCompat.Light.DarkActionBar">
        <item name="windowNoTitle">true</item>
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowBackground">@android:color/transparent</item>
        <item name="android:windowNoTitle">true</item>
        <item name="windowActionBar">false</item>
        <item name="android:windowAnimationStyle">@null</item>
    </style>

    <style name="wrap_view">
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
    </style>

    <style name="fullline_view">
        <item name="android:layout_width">fill_parent</item>
        <item name="android:layout_height">wrap_content</item>
    </style>

    <!-- app main menu style start! -->
    <!-- 菜单layout的样式 -->
    <style name="MenuItemLayoutStyle">
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:minHeight">55dip</item>
        <item name="android:gravity">center_vertical</item>
        <item name="android:orientation">horizontal</item>
        <item name="android:paddingLeft">15dip</item>
        <item name="android:paddingRight">15dip</item>
        <item name="android:background">?attr/layout_item_bg</item>
    </style>

    <!-- 菜单ImageView的样式 -->
    <style name="MenuItemImageViewStyle">
        <item name="android:layout_width">24dip</item>
        <item name="android:layout_height">24dip</item>
        <item name="android:layout_marginRight">15dip</item>
    </style>

    <!-- 菜单TextView的样式 -->
    <style name="MenuItemTextViewStyle">
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:textColor">@color/drawer_menu_text</item>
        <item name="android:drawablePadding">@dimen/space_10</item>
        <item name="android:textSize">@dimen/text_size_16</item>
    </style>
    <!-- app main menu style end! -->

    <style name="TabItemAppearance" parent="TextAppearance.Design.Tab">
        <item name="android:textSize">16sp</item>
    </style>

    <!-- project list text style bgein -->
    <style name="project_list_text_parent">
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
    </style>

    <!-- viewpage文本  滑动标签标题 -->
    <style name="viewpage_slidingTabTitle">
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:gravity">center</item>
        <item name="android:textColor">@color/viewpage_selector_slide_title</item>
        <item name="android:textSize">17sp</item>
    </style>

    <style name="text_base" parent="@style/wrap_view">
        <item name="android:textSize">@dimen/text_regular_primary_size</item>
        <item name="android:textColor">@color/text_dark</item>
        <item name="android:ellipsize">end</item>
        <item name="android:maxLines">1</item>
        <item name="android:singleLine">true</item>
    </style>

    <style name="text_multiline" parent="@style/text_base">
        <item name="android:maxLines">5</item>
        <item name="android:singleLine">false</item>
        <item name="android:lineSpacingMultiplier">1.15</item>
    </style>

    <style name="item_input_container">
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:background">@drawable/textfield_selector</item>
        <item name="android:gravity">center_vertical</item>
        <item name="android:orientation">horizontal</item>
        <item name="android:paddingLeft">8dp</item>
    </style>

    <style name="item_input_edittext">
        <item name="android:layout_width">0dp</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:layout_weight">1</item>
        <item name="android:background">@null</item>
        <item name="android:minHeight">40dp</item>
        <item name="android:singleLine">true</item>
        <item name="android:textColor">@color/main_black</item>
        <item name="android:textColorHint">@color/main_gray</item>
        <item name="android:textSize">@dimen/text_size_16</item>
    </style>

    <style name="item_input_clear">
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:background">@drawable/btn_clear_input_selector</item>
        <item name="android:contentDescription">@null</item>
    </style>

    <style name="button_common_blue">
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">38dp</item>
        <item name="android:background">@drawable/btn_blue_selector</item>
        <item name="android:textColor">@color/white</item>
        <item name="android:textSize">@dimen/text_size_16</item>
    </style>

    <style name="list_cell_text">
        <item name="android:textSize">16.0dip</item>
        <item name="android:textColor">@color/white</item>
        <item name="android:ellipsize">end</item>
        <item name="android:gravity">center_vertical</item>
        <item name="android:layout_width">fill_parent</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:maxLines">1</item>
        <item name="android:singleLine">true</item>
    </style>

    <style name="list_cell_text_dialog" parent="@style/list_cell_text">
        <item name="android:textSize">16.0dip</item>
        <item name="android:textColor">@color/ui_dialog_list_text</item>
    </style>

    <style name="list_cell_divider">
        <item name="android:layout_gravity">bottom</item>
        <item name="android:background">#cccccc</item>
        <item name="android:layout_width">fill_parent</item>
        <item name="android:layout_height">1.0px</item>
        <item name="android:layout_alignParentBottom">true</item>
    </style>

    <style name="dialog_common" parent="@style/Theme.AppCompat.Dialog">
        <item name="android:windowBackground">@mipmap/dialog_background</item>
    </style>

    <style name="dialog_bottom" parent="@style/dialog_common">
        <item name="android:windowBackground">@mipmap/dialog_bottom_background</item>
        <item name="android:windowAnimationStyle">@style/dialog_animation</item>
    </style>

    <style name="quick_option_dialog" parent="@style/dialog_common">
        <item name="android:windowBackground">@color/white40</item>
        <item name="android:windowAnimationStyle">@style/dialog_animation</item>
    </style>

    <style name="dialog_animation" parent="android:Animation">
        <item name="@android:windowEnterAnimation">@anim/dialog_enter</item>
        <item name="@android:windowExitAnimation">@anim/dialog_exit</item>
    </style>

    <!-- 列表用户头像的样式 -->
    <style name="UserFaceImageStyle">
        <item name="android:layout_width">40.0dip</item>
        <item name="android:layout_height">40.0dip</item>
        <item name="android:padding">1.0dip</item>
        <item name="android:clickable">true</item>
        <item name="android:contentDescription">face</item>
        <item name="android:src">@mipmap/widget_dface</item>
    </style>

    <style name="dialog_waiting" parent="@android:style/Theme.Dialog">
        <item name="android:windowBackground">@mipmap/dialog_background</item>
    </style>

    <style name="dialog_button">
        <item name="android:textSize">@dimen/text_regular_primary_size</item>
        <item name="android:textColor">@color/text_dark</item>
        <item name="android:gravity">center</item>
        <item name="android:layout_gravity">center_vertical</item>
        <item name="android:background">@drawable/touch_clear_bg</item>
        <item name="android:visibility">gone</item>
        <item name="android:layout_width">0.0dip</item>
        <item name="android:layout_height">46.0dip</item>
        <item name="android:maxLines">2</item>
        <item name="android:layout_weight">1.0</item>
    </style>

    <style name="dialog_divider">
        <item name="android:layout_gravity">bottom</item>
        <item name="android:background">@color/light_gray</item>
        <item name="android:layout_width">fill_parent</item>
        <item name="android:layout_height">1.0px</item>
        <item name="android:layout_alignParentBottom">true</item>
    </style>

    <style name="dialog_pinterest_text" parent="@style/text_multiline">
        <item name="android:textSize">@dimen/text_regular_primary_size</item>
        <item name="android:textColor">@color/text_dark</item>
        <item name="android:layout_width">fill_parent</item>
    </style>

    <style name="dialog_subtitle" parent="@style/fullline_view">
        <item name="android:textSize">@dimen/text_large_secondary_size</item>
        <item name="android:textColor">@color/text_light</item>
        <item name="android:gravity">center_vertical</item>
        <item name="android:maxLines">2</item>
        <item name="android:lineSpacingMultiplier">1.2</item>
    </style>

    <style name="dialog_text">
        <item name="android:textSize">@dimen/text_large_secondary_size</item>
        <item name="android:textColor">@color/text_light</item>
        <item name="android:layout_width">fill_parent</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:layout_marginBottom">@dimen/global_dialog_padding</item>
        <item name="android:lineSpacingMultiplier">1.3</item>
    </style>

    <style name="dialog_title" parent="@style/fullline_view">
        <item name="android:textSize">@dimen/text_large_primary_size</item>
        <item name="android:textStyle">normal</item>
        <item name="android:textColor">@color/text_dark</item>
        <item name="android:gravity">center_vertical</item>
    </style>

    <style name="section_item_divider">
        <item name="android:background">@color/ui_dialog_divider</item>
        <item name="android:layout_width">fill_parent</item>
        <item name="android:layout_height">1.0px</item>
    </style>

    <style name="section_item_divider_vertical">
        <item name="android:background">@color/ui_dialog_divider</item>
        <item name="android:layout_width">0.1px</item>
        <item name="android:layout_height">fill_parent</item>
    </style>

    <style name="user_face_image">
        <item name="android:layout_width">40.0dip</item>
        <item name="android:layout_height">40.0dip</item>
        <item name="android:padding">1.0dip</item>
        <item name="android:clickable">true</item>
        <item name="android:src">@mipmap/widget_dface</item>
    </style>

    <style name="comment_user_face_image">
        <item name="android:layout_width">28.0dip</item>
        <item name="android:layout_height">28.0dip</item>
        <item name="android:padding">1.0dip</item>
        <item name="android:clickable">true</item>
        <item name="android:src">@mipmap/widget_dface</item>
    </style>

    <style name="toolbar_action">
        <item name="android:gravity">center</item>
        <item name="android:layout_gravity">center</item>
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">fill_parent</item>
        <item name="android:scaleType">center</item>
        <item name="android:minWidth">44.0dip</item>
        <item name="android:layout_weight">0.0</item>
    </style>

    <style name="toolbar_action_comment">
        <item name="android:textSize">8.0sp</item>
        <item name="android:textColor">@color/white</item>
        <item name="android:gravity">center</item>
        <item name="android:layout_gravity">center</item>
        <item name="android:background">@color/main_green</item>
        <item name="android:paddingLeft">2.0dip</item>
        <item name="android:paddingRight">2.0dip</item>
        <item name="android:paddingTop">2.0dip</item>
        <item name="android:paddingBottom">2.0dip</item>
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:layout_marginLeft">10.0dip</item>
        <item name="android:layout_marginTop">-8.0dip</item>
        <item name="android:maxWidth">44.0dip</item>
        <item name="android:minWidth">12.0dip</item>
        <item name="android:singleLine">true</item>
        <item name="android:includeFontPadding">false</item>
    </style>

    <!-- 加载滚动条样式 -->
    <style name="loading">
        <item name="android:indeterminate">true</item>
        <item name="android:indeterminateDrawable">@drawable/progressloading</item>
        <item name="android:indeterminateDuration">1000</item>
        <item name="android:indeterminateOnly">true</item>
    </style>

    <!-- 操作项样式 start -->
    <style name="option_item_rl">
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:background">@drawable/ic_bg_item_selector</item>
        <item name="android:clickable">true</item>
        <item name="android:padding">@dimen/space_13</item>
        <item name="android:gravity">center_vertical</item>
        <item name="android:orientation">horizontal</item>
    </style>

    <style name="option_item_img">
        <item name="android:layout_width">20dp</item>
        <item name="android:layout_height">20dp</item>
        <item name="android:layout_marginRight">@dimen/space_10</item>
    </style>

    <style name="option_item_text_parent">
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:layout_marginRight">@dimen/space_4</item>
        <item name="android:gravity">center_vertical</item>
        <item name="android:textColor">@color/main_black</item>
        <item name="android:clickable">false</item>
        <item name="android:layout_centerVertical">true</item>
        <item name="android:textSize">@dimen/text_size_16</item>
    </style>

    <style name="option_item_text" parent="@style/option_item_text_parent">
        <item name="android:drawablePadding">@dimen/space_8</item>
        <item name="android:textColor">?attr/textColor</item>
    </style>

    <style name="option_item_text_fa" parent="@style/option_item_text_parent">
        <item name="android:layout_marginRight">10dp</item>
        <item name="android:textColor">?android:textColorLink</item>
        <item name="android:textSize">22sp</item>
    </style>

    <style name="option_item_goto_right">
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:layout_alignParentRight">true</item>
        <item name="android:layout_centerVertical">true</item>
        <item name="android:src">@mipmap/ic_item_goto_right_tip</item>
        <item name="android:layout_marginRight">@dimen/space_10</item>
    </style>

    <style name="option_item_toggleButton">
        <item name="android:layout_width">45dp</item>
        <item name="android:layout_height">20dp</item>
    </style>

    <!-- 操作项样式end -->

    <!-- 分享对话框样式 start -->
    <style name="dialog_content_share_ll">
        <item name="android:layout_width">0dp</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:layout_weight">1</item>
        <item name="android:gravity">center_horizontal</item>
        <item name="android:orientation">vertical</item>
    </style>

    <style name="dialog_content_share_text">
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:drawableTop">@drawable/share_icon_qq_selector</item>
        <item name="android:drawablePadding">@dimen/space_4</item>
        <item name="android:textColor">@color/main_gray</item>
        <item name="android:gravity">center</item>
        <item name="android:textSize">@dimen/text_size_12</item>
    </style>
    <!-- 分享对话框样式 end -->

    <!-- quick option style start -->
    <style name="quick_option_item">
        <item name="android:layout_width">0dp</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:layout_weight">1</item>
        <item name="android:gravity">center_horizontal</item>
        <item name="android:orientation">vertical</item>
        <item name="android:padding">@dimen/space_16</item>
    </style>

    <style name="quick_option_img">
        <item name="android:layout_width">48dp</item>
        <item name="android:layout_height">48dp</item>
    </style>

    <style name="quick_option_item_text">
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:layout_marginTop">@dimen/space_12</item>
        <item name="android:textColor">@color/drawer_menu_text</item>
        <item name="android:textSize">@dimen/text_size_12</item>
    </style>
    <!-- quick option style end -->

    <style name="uset_information_ll">
        <item name="android:layout_width">0dp</item>
        <item name="android:layout_height">match_parent</item>
        <item name="android:layout_weight">1</item>
        <item name="android:clickable">true</item>
        <item name="android:gravity">center_horizontal</item>
        <item name="android:background">@drawable/selector_user_info_tab_item</item>
        <item name="android:orientation">vertical</item>
    </style>

    <style name="user_formation_text">
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:textColor">@color/white</item>
        <item name="android:textSize">12sp</item>
    </style>

    <style name="user_formation_info" parent="@style/user_formation_text">
        <item name="android:textSize">@dimen/text_size_12</item>
    </style>

    <style name="note_detail_menu">
        <item name="android:layout_height">30dp</item>
        <item name="android:layout_width">30dp</item>
    </style>

    <style name="note_detail_menu_item" parent="note_detail_menu">
        <item name="android:layout_marginTop">5dp</item>
        <item name="android:layout_marginBottom">5dp</item>
    </style>

    <style name="note_detail_menu_setup" parent="note_detail_menu">
        <item name="android:layout_marginLeft">5dp</item>
        <item name="android:layout_marginRight">5dp</item>
    </style>

    <style name="dialog_event_apply_edittext">
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:background">@drawable/comment_edittext_selector</item>
        <item name="android:gravity">top</item>
        <item name="android:textColor">@color/main_black</item>
        <item name="android:textColorHint">@color/main_gray</item>
        <item name="android:padding">@dimen/space_5</item>
        <item name="android:textSize">@dimen/text_size_14</item>
    </style>

    <style name="dialog_event_apply_text">
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:layout_marginBottom">@dimen/space_2</item>
        <item name="android:textColor">@color/main_gray</item>
        <item name="android:textSize">@dimen/text_size_12</item>
        <item name="android:layout_marginTop">@dimen/space_10</item>
    </style>

    <style name="Theme.AppStartLoad" parent="android:Theme.Black.NoTitleBar.Fullscreen">
        <item name="android:windowBackground">@mipmap/welcome</item>
        <item name="android:windowNoTitle">true</item>
    </style>

    <style name="soft_detail_btn">
        <item name="android:layout_width">0dp</item>
        <item name="android:layout_height">32dp</item>
        <item name="android:layout_marginLeft">@dimen/space_20</item>
        <item name="android:layout_weight">1</item>
        <item name="android:background">@drawable/btn_green_selector</item>
        <item name="android:textColor">@color/white</item>
        <item name="android:textSize">@dimen/text_size_16</item>
    </style>

    <!-- events list style start -->

    <!-- events title -->
    <style name="events_list_title">
        <item name="android:layout_width">fill_parent</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:includeFontPadding">false</item>
        <item name="android:textColor">#999999</item>
        <item name="android:textSize">@dimen/text_size_12</item>
    </style>

    <style name="events_list_content">
        <item name="android:layout_width">fill_parent</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:layout_marginTop">8dip</item>
        <item name="android:textColor">#999999</item>
        <item name="android:textSize">@dimen/text_size_15</item>
    </style>

    <style name="events_list_commits">
        <item name="android:layout_width">fill_parent</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:layout_marginTop">8dip</item>
        <item name="android:textColor">#999999</item>
        <item name="android:tag">1</item>
        <item name="android:textSize">@dimen/text_size_15</item>
    </style>

    <style name="events_list_client">
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:layout_marginRight">10dip</item>
        <item name="android:textColor">#999999</item>
        <item name="android:textSize">@dimen/text_size_10</item>
        <item name="android:visibility">gone</item>
    </style>

    <style name="events_list_data">
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:textColor">#999999</item>
        <item name="android:textSize">@dimen/text_size_10</item>
    </style>

    <!-- events list style end -->

    <style name="myissue_text" parent="@style/fill_wrap">
        <item name="android:textColor">#999999</item>
        <item name="android:textSize">15sp</item>
        <item name="android:gravity">center</item>
    </style>

    <style name="myissue_text_num" parent="@style/myissue_text">
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_alignParentRight">true</item>
        <item name="android:text">0</item>
    </style>

    <style name="team_user_infor" parent="@style/wrap_wrap">
        <item name="android:padding">5dp</item>
        <item name="android:textColor">?attr/textColor</item>
    </style>

    <style name="SpinnerDropDownListView" parent="@style/Widget.AppCompat.Light.ListView.DropDown">
        <item name="android:divider">#3f3f3f</item>
        <item name="android:dividerHeight">1dp</item>
    </style>

    <style name="mylistPopupWindowStyle" parent="@style/Widget.AppCompat.Light.PopupMenu">
        <item name="android:dropDownSelector">#343434</item>
        <item name="android:popupBackground">#343434</item>
    </style>

    <!--Created by fei on 2016/5/19.-->
    <style name="ques_bt_styles">
        <item name="android:layout_marginTop">10dp</item>
        <item name="android:layout_height">25dp</item>
        <item name="android:layout_width">48dp</item>
        <item name="android:layout_marginBottom">10dp</item>
        <item name="android:textSize">13sp</item>
        <item name="android:layout_marginLeft">4dp</item>
        <item name="android:layout_marginRight">4dp</item>
        <item name="android:background">@drawable/ques_bt_bg</item>
        <item name="android:textColor">@color/ques_bt_text_color_light</item>
    </style>

    <style name="blog_bt_styles" parent="@style/ques_bt_styles">
        <item name="android:layout_height">25dp</item>
        <item name="android:paddingLeft">12dp</item>
        <item name="android:paddingRight">12dp</item>
        <item name="android:paddingTop">4dp</item>
        <item name="android:paddingBottom">4dp</item>
        <item name="android:layout_marginBottom">10dp</item>
        <item name="android:layout_width">wrap_content</item>
    </style>

    <style name="Theme.Dialog.NoTitle.Translucent" parent="Theme.AppCompat.Light.Dialog">
        <item name="android:windowFrame">@null</item><!-- 边框 -->
        <item name="android:windowIsFloating">true</item><!-- 是否浮现在activity之上 -->
        <item name="android:windowIsTranslucent">true</item><!-- 半透明 -->
        <item name="windowNoTitle">true</item><!-- 无标题 -->
        <item name="android:windowBackground">@android:color/transparent</item><!-- 背景透明 -->
        <item name="android:backgroundDimEnabled">true</item><!-- 模糊 -->
        <item name="windowActionBar">false</item>
    </style>
</resources>


text:
aliases: /2018/08/21/boostrapping-etcd-cluster-with-tls-using-kubeadm/
author: slowe
categories: Tutorial
comments: true
date: 2018-08-21T13:00:00Z
tags:
- etcd
- CLI
- Linux
- Security
- Encryption
title: Bootstrapping an etcd Cluster with TLS using Kubeadm
url: /2018/08/21/bootstrapping-etcd-cluster-with-tls-using-kubeadm/
---

The [etcd distributed key-value store][link-4] is an integral part of [Kubernetes][link-5]. I first wrote about etcd back in 2014 in [this post][xref-1], but haven't really discussed it in any great detail since then. However, as part of my recent efforts to dive _much_ deeper into Kubernetes, I needed to revisit etcd. In this post, I wanted to share how to boostrap a new etcd cluster with TLS certificates using `kubeadm`.<!--more-->

Before I go on, I feel compelled to state that this is certainly not the _only_ way to bootstrap an etcd cluster with TLS certificates. I feel I must also state that nothing in what I'm about to share is new, novel, revolutionary, or unusual. In fact, a fair amount of it is based on [these instructions][link-10], although this post will focus on using systemd unit files instead of static pods under Kubernetes. I'm simply documenting it here in the hopes of getting the information more broadly disseminated, and to help document my own journey of learning.

## Preparing the Systems

Before you bootstrap the etcd cluster, you'll first need to prepare the nodes for the process. Although I'll list the steps manually below, in practice you'll want to build some automation tooling to help with this process. (My ["learning-tools" GitHub repository][link-3] has [an example][link-6] that you could use as a starting point for your own tooling.)

1. You'll need to download an etcd release from GitHub.

2. Unpack the release tarball and copy the `etcd` and `etcdctl` binaries to somewhere in your path, like `/usr/local/bin`. (Those two binaries are all you need.)

3. Create a data directory for etcd to use, like `/var/lib/etcd`.

4. Download the `kubeadm` binary and place it somewhere in your path, like `/usr/local/bin`. I prefer downloading the `kubeadm` binary as opposed to using package management, as package management also installs some other packages that aren't needed in this case. Use [this page][link-9] to see how to download `kubeadm` (just substitute `kubeadm` for `kubectl`). Note that this procedure was tested with `kubeadm` version 1.11.2; other versions _should_ work fine but I can't guarantee it.

You'll need to repeat this process for each system that will participate in the etcd cluster.

Once you've completed these steps, then you're ready to proceed with boostrapping the etcd cluster with TLS encryption and TLS client authentication.

## Bootstrapping the etcd Cluster

With all the binaries in place, you'll start by generating all the certificates that are needed. This is where you'll leverage `kubeadm`; specifically, the `kubeadm alpha phase certs` command.

First, create a self-signed CA for etcd:

    kubeadm alpha phase certs etcd-ca

This will create a CA certificate and key in `/etc/kubernetes/pki/etcd`. The files will be named `ca.crt` and `ca.key`. Copy these files to the same location on the other etcd nodes (you may need to create the directory structure first with `mkdir -p`).

Before you can continue with the next steps---generating server and peer certificates---you'll need to first create a configuration file for `kubeadm` that provides some additional instructions on how to create those certificates. Specifically, this configuration file will instruct `kubeadm` on which Subject Alternative Names (SANs) should be included on the certificates.

Here's the configuration file (this is for an EC2 instance in the "us-west-2" region with the private IP address 192.168.1.100, substitute your correct values here):

``` yaml
apiVersion: "kubeadm.k8s.io/v1alpha2"
kind: MasterConfiguration
etcd:
  local:
    serverCertSANs:
      - "ip-192-168-1-100.us-west-2.compute.internal"
      - "192.168.1.100"
    peerCertSANs:
      - "ip-192-168-1-100.us-west-2.compute.internal"
```

This configuration file syntax is specific to 1.11 (and possibly newer); it won't work for 1.10. Also, play close attention to capitalization and spacing (`kubeadm` is very particular).

With the `kubeadm` configuration in place, you can create the etcd server certificate (assuming the configuration file is stored as `etcd.yaml`):

    kubeadm alpha phase certs etcd-server --config etc.yaml

This will create a `server.crt` and `server.key` in `/etc/kubernetes/pki/etcd`. Repeat this process on the other etcd nodes---don't copy certificates across nodes as the hostnames on the certificate won't match up. Make sure you appropriately customize the `etcd.yaml` configuration file for each host so that the hostnames and IP addresses assigned to the certificates are correct.

Next, create the etcd peer certificates:

    kubeadm alpha phase certs etcd-peer --config etcd.yaml

This creates two files (`peer.crt` and `peer.key`) in the same directory as the previous steps (`/etc/kubernetes/pki/etcd`). As with the previous step, repeat this command on the other etcd nodes; don't copy certificates around.

You now have the etcd binaries in place and have all the necessary certificates for securing etcd. The next step is to create the systemd unit file that will start etcd. It should look something like this:

```
[Unit]
Description=etcd
Documentation=https://github.com/coreos/etcd
Conflicts=etcd2.service
Wants=network-online.target network.target
After=network-online.target

[Service]
Type=notify
Restart=always
RestartSec=5s
LimitNOFILE=40000
TimeoutStartSec=0
EnvironmentFile=/etc/etcd/etcd.conf
ExecStart=/usr/local/bin/etcd

[Install]
WantedBy=multi-user.target
```

The systemd unit references an environment file to keep the systemd unit file as simple and straightforward as possible. Here's the environment file that would go along with this systemd unit file:

```
ETCD_NAME="node1"
ETCD_DATA_DIR="/var/lib/etcd"
ETCD_LISTEN_CLIENT_URLS="https://0.0.0.0:2379"
ETCD_LISTEN_PEER_URLS="https://0.0.0.0:2380"
ETCD_ADVERTISE_CLIENT_URLS="https://192.168.1.100:2379"
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.1.100:2380"
ETCD_INITIAL_CLUSTER="node1=https://192.168.1.100:2380,\
node2=https://192.168.1.101:2380,\
node3=https://192.168.1.102:2380
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_INITIAL_CLUSTER_TOKEN="new-cluster"
ETCD_TRUSTED_CA_FILE="/etc/kubernetes/pki/etcd/ca.crt"
ETCD_CERT_FILE="/etc/kubernetes/pki/etcd/server.crt"
ETCD_KEY_FILE="/etc/kubernetes/pki/etcd/server.key"
ETCD_CLIENT_CERT_AUTH="true"
ETCD_PEER_TRUSTED_CA_FILE="/etc/kubernetes/pki/etcd/ca.crt"
ETCD_PEER_CERT_FILE="/etc/kubernetes/pki/etcd/peer.crt"
ETCD_PEER_KEY_FILE="/etc/kubernetes/pki/etcd/peer.key"
ETCD_PEER_CLIENT_CERT_AUTH="true"
```

Note that you **must** customize this environment file for each system in the cluster! Be sure to set the `ETCD_NAME`, `ETCD_ADVERTISE_CLIENT_URLS`, and `ETCD_INITIAL_ADVERTISE_PEER_URLS` values to the correct values for each system. Also be sure that the names and IP addresses referenced in `ETCD_INITIAL_CLUSTER` correctly match the names (as specified by `ETCD_NAME`) and IP addresses of the systems in the cluster.

Because you've modified systemd's configuration by adding a new unit file, you'll need to run `systemctl daemon-reload`, and then you can enable and start etcd:

    systemctl enable etcd
    systemctl start etcd

Use `systemctl status etcd` and/or `journalctl -u etcd` to make sure that the cluster formed, a leader was elected, and that etcd is serving client requests.

The final step is just to verify that etcd is working as expected. You can use `etcdctl` to perform this test:

    ETCDCTL_API=3 etcdctl --cacert=/etc/kubernetes/pki/etcd/ca.crt \
    --cert=/etc/kubernetes/pki/etcd/peer.crt \
    --key=/etc/kubernetes/pki/etcd/peer.key \
    --endpoints=https://192.168.1.100:2379,https://192.168.1.101:2379,\
    https://192.168.1.102:2379
    endpoint health

It may be obvious but it's worth pointing out/reminding readers that you'll need to customize the `--endpoints=` parameter to reflect the correct IP addresses of the systems in your cluster.

This `etcdctl` command looks complicated, but it's necessary for a couple reasons (see [here][link-8] for more details on this command):

* This is an etcd version 3 cluster, so you have to explicitly tell `etcdctl` to use the version 3 API.
* Because client certification authentication is enabled, you can't make a connection to the etcd cluster without a client certificate. Hence, you need to specify all the various certificate-related flags.

Assuming the `etcdctl` command worked correctly and reported no errors (all cluster endpoints healthy), then you're all set!

## Additional Resources

Virtually everyone who does content creation stands on the shoulders of those who have gone before them, and I'm no exception. Refer to these resources for more information or additional perspectives on this topic:

[etcd Security Model][link-1]
[The "Bootstrapping the etcd Cluster" portion of Kelsey Hightower's Kubernetes the Hard Way repository][link-2]

[This GitHub repository][link-7] by my colleague Duffie Cooley also provided some inspiration and guidance for some portions of this process.

**UPDATE 2020-01-31:** Note that the `kubeadm alpha phase` command was replaced by the `kubeadm init phase` command in the Kubernetes 1.13 release. Since readers are pretty likely to be running a release later than 1.13, please replace all instances of `kubeadm alpha phase` above with `kubeadm init phase`. The commands remain otherwise identical.

[link-1]: https://coreos.com/etcd/docs/latest/op-guide/security.html
[link-2]: https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/07-bootstrapping-etcd.md
[link-3]: https://github.com/scottslowe/learning-tools/
[link-4]: https://github.com/coreos/etcd/
[link-5]: https://kubernetes.io/
[link-6]: https://github.com/scottslowe/learning-tools/tree/master/etcd/etcdv3-ansible-aws-tf
[link-7]: https://github.com/mauilion/wardroom-nc/
[link-8]: https://github.com/coreos/etcd/tree/master/etcdctl
[link-9]: https://kubernetes.io/docs/tasks/tools/install-kubectl/#install-kubectl-binary-via-curl
[link-10]: https://kubernetes.io/docs/setup/independent/setup-ha-etcd-with-kubeadm/
[xref-1]: {{< relref "2014-08-18-coreos-continued-etcd.md" >}}

redpajama_set_name: RedPajamaGithub


text:
import * as fs from "fs"
import { when } from "mobx"
import { ShopStore } from "./ShopStore"

const bookFetcher = () => Promise.resolve(JSON.parse(fs.readFileSync("./public/books.json")))

it("bookstore fetches data", (done) => {
    const store = ShopStore.create({}, { fetch: bookFetcher })
    when(
        () => store.isLoading === false,
        () => {
            expect(store.books.size).toBe(4)
            expect(store.books.get("978-1933988177").price).toBe(30.5)
            done()
        }
    )
})

it("bookstore sorts data", (done) => {
    const store = ShopStore.create({}, { fetch: bookFetcher })
    when(
        () => store.isLoading === false,
        () => {
            expect(store.sortedAvailableBooks.map((book) => book.name)).toEqual([
                "Lucene in Action, Second Edition",
                "Sophie's World : The Greek Philosophers",
                "The Lightning Thief",
                "The Sea of Monsters"
            ])
            done()
        }
    )
})


text:
<?php
defined('BASEPATH') OR exit('No direct script access allowed');

/*
|--------------------------------------------------------------------------
| Display Debug backtrace
|--------------------------------------------------------------------------
|
| If set to TRUE, a backtrace will be displayed along with php errors. If
| error_reporting is disabled, the backtrace will not display, regardless
| of this setting
|
*/
defined('SHOW_DEBUG_BACKTRACE') OR define('SHOW_DEBUG_BACKTRACE', TRUE);

/*
|--------------------------------------------------------------------------
| File and Directory Modes
|--------------------------------------------------------------------------
|
| These prefs are used when checking and setting modes when working
| with the file system.  The defaults are fine on servers with proper
| security, but you may wish (or even need) to change the values in
| certain environments (Apache running a separate process for each
| user, PHP under CGI with Apache suEXEC, etc.).  Octal values should
| always be used to set the mode correctly.
|
*/
defined('FILE_READ_MODE')  OR define('FILE_READ_MODE', 0644);
defined('FILE_WRITE_MODE') OR define('FILE_WRITE_MODE', 0666);
defined('DIR_READ_MODE')   OR define('DIR_READ_MODE', 0755);
defined('DIR_WRITE_MODE')  OR define('DIR_WRITE_MODE', 0755);

/*
|--------------------------------------------------------------------------
| File Stream Modes
|--------------------------------------------------------------------------
|
| These modes are used when working with fopen()/popen()
|
*/
defined('FOPEN_READ')                           OR define('FOPEN_READ', 'rb');
defined('FOPEN_READ_WRITE')                     OR define('FOPEN_READ_WRITE', 'r+b');
defined('FOPEN_WRITE_CREATE_DESTRUCTIVE')       OR define('FOPEN_WRITE_CREATE_DESTRUCTIVE', 'wb'); // truncates existing file data, use with care
defined('FOPEN_READ_WRITE_CREATE_DESTRUCTIVE')  OR define('FOPEN_READ_WRITE_CREATE_DESTRUCTIVE', 'w+b'); // truncates existing file data, use with care
defined('FOPEN_WRITE_CREATE')                   OR define('FOPEN_WRITE_CREATE', 'ab');
defined('FOPEN_READ_WRITE_CREATE')              OR define('FOPEN_READ_WRITE_CREATE', 'a+b');
defined('FOPEN_WRITE_CREATE_STRICT')            OR define('FOPEN_WRITE_CREATE_STRICT', 'xb');
defined('FOPEN_READ_WRITE_CREATE_STRICT')       OR define('FOPEN_READ_WRITE_CREATE_STRICT', 'x+b');

/*
|--------------------------------------------------------------------------
| Exit Status Codes
|--------------------------------------------------------------------------
|
| Used to indicate the conditions under which the script is exit()ing.
| While there is no universal standard for error codes, there are some
| broad conventions.  Three such conventions are mentioned below, for
| those who wish to make use of them.  The CodeIgniter defaults were
| chosen for the least overlap with these conventions, while still
| leaving room for others to be defined in future versions and user
| applications.
|
| The three main conventions used for determining exit status codes
| are as follows:
|
|    Standard C/C++ Library (stdlibc):
|       http://www.gnu.org/software/libc/manual/html_node/Exit-Status.html
|       (This link also contains other GNU-specific conventions)
|    BSD sysexits.h:
|       http://www.gsp.com/cgi-bin/man.cgi?section=3&topic=sysexits
|    Bash scripting:
|       http://tldp.org/LDP/abs/html/exitcodes.html
|
*/
defined('EXIT_SUCCESS')        OR define('EXIT_SUCCESS', 0); // no errors
defined('EXIT_ERROR')          OR define('EXIT_ERROR', 1); // generic error
defined('EXIT_CONFIG')         OR define('EXIT_CONFIG', 3); // configuration error
defined('EXIT_UNKNOWN_FILE')   OR define('EXIT_UNKNOWN_FILE', 4); // file not found
defined('EXIT_UNKNOWN_CLASS')  OR define('EXIT_UNKNOWN_CLASS', 5); // unknown class
defined('EXIT_UNKNOWN_METHOD') OR define('EXIT_UNKNOWN_METHOD', 6); // unknown class member
defined('EXIT_USER_INPUT')     OR define('EXIT_USER_INPUT', 7); // invalid user input
defined('EXIT_DATABASE')       OR define('EXIT_DATABASE', 8); // database error
defined('EXIT__AUTO_MIN')      OR define('EXIT__AUTO_MIN', 9); // lowest automatically-assigned error code
defined('EXIT__AUTO_MAX')      OR define('EXIT__AUTO_MAX', 125); // highest automatically-assigned error code

# User Constant
defined('LOREM_IPSUM')        OR define('LOREM_IPSUM',
    "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
    Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
    Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
    Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
);


text:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">

<meta http-equiv="content-type" content="text/html; charset=utf-8" >
<title>Berlin 2014
 -  Proposal</title>
<meta name="author" content="Benjamin Reitzammer" >

<link rel="alternate" type="application/rss+xml" title="devopsdays RSS Feed" href="http://www.devopsdays.org/feed/" >

<link rel="stylesheet" href="/css/devops.min.css" type="text/css" media="screen, projection">
<link rel="stylesheet" href="/css/blueprint/print.css" type="text/css" media="print">

      Home

      Contact

      Events

      Presentations

      Blog

Berlin 2014
 -  Proposal

Gold sponsors

    Welcome
    Program

    Location
    Contact

    Conduct
    Presse

Back to proposals overview - program

Sane Secrets Sharing

Abstract:

I want to present a simple yet fully functional way of sharing secrets in a team
and using them in a configuration management tool.
The approach builds on the Unix philosophy and combines multiple tools in an
easy way and should be applicable by any team with very small effort, yet still
provides reasonable security.

The procedure is used in production and has proven itself well for our team of
three involved people.

I'll demonstrate the approach in a format that's both Ignite-compatible and is
close to live-coding demos.

Speaker:

Benjamin Reitzammer

Please enable JavaScript to view the comments powered by Disqus.
blog comments powered by Disqus

Silver sponsors

Evening sponsor

Partners


text:
window.addEventListener('load', function(){
	var link = document.querySelector('a.ifttt'),
		box = document.querySelector('div.ifttt-recipes'),
		blocker = document.querySelector('div.blocker'),
		first = true,
		recipeLinks = [
						'https://ifttt.com/recipe_embed/265226',
						'https://ifttt.com/recipe_embed/265241',
						'https://ifttt.com/recipe_embed/265243'
		],
		frameStart = '<iframe scrolling="no" src="',
		frameEnd = '" style="display: inline-block; border-style: solid; border-width: 0px; width: 100%; height: 90px; min-width: 220px; max-width: 640px; padding: 0px; border-radius: 5px; margin: 5px 0px;"></iframe>';

	function hideBox(){
		box.style.bottom = -box.clientHeight - 100 + 'px';
		blocker.style.opacity = 0;
		window.setTimeout(function(){
			blocker.style.display = 'none';
		},500);
	}

	function showBox(){
		if(first){
			var frames = [];
			recipeLinks.forEach(function(link){
				frames.push(frameStart + link + frameEnd);
			});
			box.innerHTML = 'IFTTT Rezepte '+frames.join('');
			first = false;
		}
		box.style.left = window.innerWidth/2 - 300 + 'px';
		box.style.bottom = -box.clientHeight - 100 + 'px';
		box.style.display = 'block';
		blocker.style.display = 'block';
		window.setTimeout(function(){
			box.style.bottom = window.innerHeight/2 - box.clientHeight/2 + 'px';
			blocker.style.opacity = 0.7;
		},10);

	};

	link.addEventListener('click', showBox);
	blocker.addEventListener('click', hideBox);
});


text:
"use strict";

Object.defineProperty(exports, "__esModule", {
	value: true
});
exports.default = basicImage;

var _justExtend = require("just-extend");

var _justExtend2 = _interopRequireDefault(_justExtend);

var _base = require("./base");

var _base2 = _interopRequireDefault(_base);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var name = 'media';

var image = ['gif', 'jpg', 'jpeg', 'tiff', 'png', 'svg', 'webp'];
var video = ['ogv', 'webm', 'mp4'];
var audio = ['wav', 'mp3', 'ogg'];

function basicImage(opts) {
	var defaultOptions = {
		name: name,
		regex: new RegExp("(?:https?)://\\S*\\.(?:" + image.concat(video, audio).join('|') + ")", 'gi'),
		template: function template(args) {
			var url = args[0];
			var ext = url.split('.').slice(-1)[0];
			if (image.indexOf(ext) >= 0) {
				return "<img class=\"ejs-embed\" src=\"" + url + "\"/>";
			} else if (video.indexOf(ext) >= 0) {
				return "<video src=\"" + url + "\" controls class=\"ejs-video\"></video>";
			} else if (audio.indexOf(ext) >= 0) {
				return "<audio src=\"" + url + "\" controls class=\"ejs-audio\"></audio>";
			}
		}
	};
	var pluginOptions = (0, _justExtend2.default)({}, defaultOptions, opts);
	return (0, _base2.default)(pluginOptions);
}

basicImage.id = name;


text:
package xdgbasedir

import (
	"os"
	"path/filepath"
	"runtime"
	"sync"
)

type mode int

const (
	// Unix unix mode directory structure.
	Unix mode = iota
	// Native native mode directory structure.
	Native
)

// Mode mode of directory structure. This config only available darwin.
//
// If it is set to `Unix`, it refers to the same path as linux. If it is set to `Native`, it refers to the Apple FileSystemProgrammingGuide path.
// By default, `Unix`.
var Mode = Unix

// initOnce for run initDir once on darwin.
var initOnce sync.Once

// DataHome return the XDG_DATA_HOME based directory path.
//
// $XDG_DATA_HOME defines the base directory relative to which user specific data files should be stored.
// If $XDG_DATA_HOME is either not set or empty, a default equal to $HOME/.local/share should be used.
func DataHome() string {
	if env := os.Getenv("XDG_DATA_HOME"); env != "" {
		return expandUser(env)
	}
	return dataHome()
}

// ConfigHome return the XDG_CONFIG_HOME based directory path.
//
// $XDG_CONFIG_HOME defines the base directory relative to which user specific configuration files should be stored.
// If $XDG_CONFIG_HOME is either not set or empty, a default equal to $HOME/.config should be used.
func ConfigHome() string {
	if env := os.Getenv("XDG_CONFIG_HOME"); env != "" {
		return expandUser(env)
	}
	return configHome()
}

// DataDirs return the XDG_DATA_DIRS based directory path.
//
// $XDG_DATA_DIRS defines the preference-ordered set of base directories to search for data files in addition
// to the $XDG_DATA_HOME base directory. The directories in $XDG_DATA_DIRS should be seperated with a colon ':'.
// If $XDG_DATA_DIRS is either not set or empty, a value equal to /usr/local/share/:/usr/share/ should be used.
func DataDirs() string {
	if env := os.Getenv("XDG_DATA_DIRS"); env != "" {
		return expandUser(env)
	}
	return dataDirs()
}

// ConfigDirs return the XDG_CONFIG_DIRS based directory path.
//
// $XDG_CONFIG_DIRS defines the preference-ordered set of base directories to search for configuration files in addition
// to the $XDG_CONFIG_HOME base directory. The directories in $XDG_CONFIG_DIRS should be seperated with a colon ':'.
// If $XDG_CONFIG_DIRS is either not set or empty, a value equal to /etc/xdg should be used.
func ConfigDirs() string {
	if env := os.Getenv("XDG_CONFIG_DIRS"); env != "" {
		return expandUser(env)
	}
	return configDirs()
}

// CacheHome return the XDG_CACHE_HOME based directory path.
//
// $XDG_CACHE_HOME defines the base directory relative to which user specific non-essential data files should be stored.
// If $XDG_CACHE_HOME is either not set or empty, a default equal to $HOME/.cache should be used.
func CacheHome() string {
	if env := os.Getenv("XDG_CACHE_HOME"); env != "" {
		return expandUser(env)
	}
	return cacheHome()
}

// RuntimeDir return the XDG_RUNTIME_DIR based directory path.
//
// $XDG_RUNTIME_DIR defines the base directory relative to which user-specific non-essential runtime files and
// other file objects (such as sockets, named pipes, ...) should be stored. The directory MUST be owned by the user,
// and he MUST be the only one having read and write access to it. Its Unix access mode MUST be 0700.
//
// TODO(zchee): XDG_RUNTIME_DIR seems to change depending on the each distro or init system such as systemd.
// Also In macOS, normal user haven't permission for write to this directory.
// xref:
//	http://serverfault.com/questions/388840/good-default-for-xdg-runtime-dir/727994#727994
func RuntimeDir() string {
	if env := os.Getenv("XDG_RUNTIME_DIR"); env != "" {
		return expandUser(env)
	}
	return runtimeDir()
}

// expandUser expands shell's user home directory tilde expansion from s.
func expandUser(s string) string {
	if len(s) < 2 || s[0] != '~' || !os.IsPathSeparator(s[1]) {
		return s
	}

	env := "HOME"
	if runtime.GOOS == "windows" {
		env = "USERPROFILE"
	} else if runtime.GOOS == "plan9" {
		env = "home"
	}
	home := os.Getenv(env)
	if home == "" {
		return s
	}

	if runtime.GOOS == "windows" {
		s = filepath.ToSlash(filepath.Join(home, s[2:]))
	} else {
		s = filepath.Join(home, s[2:])
	}
	return os.Expand(s, func(env string) string {
		if env == "HOME" {
			return home
		}
		return os.Getenv(env)
	})
}


text:
#include "tensorflow/core/debug/debug_gateway.h"

#include "tensorflow/core/common_runtime/device_factory.h"
#include "tensorflow/core/common_runtime/session_factory.h"
#include "tensorflow/core/framework/tensor.h"

namespace tensorflow {

DebugGateway::DebugGateway(DirectSession* session) : session_(session) {
  session_->node_outputs_callback_ = [this](
      const string& node_name, const int output_slot, const Tensor* tensor,
      const bool is_ref, OpKernelContext* ctx) {
    if (comp_cb_ != nullptr && output_slot <= 0) {
      // The node completion callback is invoked once for a node regardless
      // of whether the node has zero, one or more outputs.
      // The output_slot can be negative (-1, or kControlSlot) if
      // node_outputs_callback_ is invoked for a node with no output. If that
      // is the case, notify the callback that the node in question has no
      // output.
      comp_cb_(node_name, output_slot == 0);
    }

    // Copy tensor values (e.g., from GPU to host) only if the
    // value callback is not nullptr.
    if (val_cb_ != nullptr && output_slot >= 0) {
      CopyTensor(
          node_name, output_slot, tensor, ctx,
          [this, node_name, output_slot, is_ref](const Tensor* copied_tensor) {
            val_cb_(node_name, output_slot, *copied_tensor, is_ref);
          });
    }

    return Status::OK();
  };
}

DebugGateway::~DebugGateway() {
  if (session_ != nullptr) {
    session_->node_outputs_callback_ = nullptr;
  }
}

void DebugGateway::SetNodeCompletionCallback(NodeCompletionCallback callback) {
  comp_cb_ = callback;
}

void DebugGateway::SetNodeValueCallback(NodeValueCallback callback) {
  val_cb_ = callback;
}

void DebugGateway::CopyTensor(const string& node_name, const int output_slot,
                              const Tensor* src_tensor, OpKernelContext* ctx,
                              CopyDoneCallback copy_done_cb) {
  Device* device = static_cast<Device*>(ctx->device());

  // Determine if the tensor is initialized properly.
  // The second part of the check is necessary because in some cases, a
  // tensor can pass the IsInitialized() check, but the dtype is not set,
  // e.g., tf.FIFOQueue.
  if (src_tensor->IsInitialized() && DataTypeSize(src_tensor->dtype()) > 0) {
    // Tensor is initialized.

    string tensor_tag = strings::StrCat(node_name, ":", output_slot);

    // Create copied tensor on host
    Allocator* cpu_allocator = tensorflow::cpu_allocator();
    Tensor cpu_tensor(cpu_allocator, src_tensor->dtype(), src_tensor->shape());

    // Determine if the tensor is on device (GPU) or host (CPU).
    // The second part of the check is necessary because even an OpKernel on
    // may have output tensors allocated on CPU.
    if ((device->name().find("gpu:") != string::npos || device->name().find("SYCL:") != string::npos) &&
        !ctx->output_alloc_attr(output_slot).on_host()) {
      // GPU tensors: Copy it to host (CPU).
      DeviceContext* device_ctxt = ctx->op_device_context();

      // Copy device (e.g., GPU) tensor to host and when done, invoke the
      // callback.
      device_ctxt->CopyDeviceTensorToCPU(
          src_tensor, "TensorCopy", device, &cpu_tensor,
          [node_name, cpu_tensor, copy_done_cb](const Status& s) {
            if (s.ok()) {
              copy_done_cb(&cpu_tensor);
            } else {
              LOG(ERROR) << "Copying of device Tensor " << node_name
                         << " to CPU for debugging failed.";
            }
          });
    } else {
      // For CPU tensors, copy the source tensor and own the copy, because the
      // value callback may outlive the life time of the tensor and the tensor
      // may shared the underlying buffer with other tensors.
      cpu_tensor.UnsafeCopyFromInternal(*src_tensor, src_tensor->dtype(),
                                        src_tensor->shape());

      copy_done_cb(&cpu_tensor);
    }
  } else {
    // Tensor is not initialized: No need to copy.
    copy_done_cb(src_tensor);
  }
}

}  // namespace tensorflow


text:
from django import template

register = template.Library()

@register.inclusion_tag('smartmenus/core_css.html')
def smartmenus_core_css(): pass

@register.inclusion_tag('smartmenus/theme_css.html')
def smartmenus_theme_css(theme):
    return {'theme': theme}

@register.inclusion_tag('smartmenus/smartmenus_css.html')
def smartmenus_css(theme):
    return {'theme': theme}

@register.inclusion_tag('smartmenus/core_js.html')
def smartmenus_core_js(): pass

@register.inclusion_tag('smartmenus/init_js.html')
def smartmenus_init_js(): pass

@register.inclusion_tag('smartmenus/smartmenus_js.html')
def smartmenus_js(): pass

@register.inclusion_tag('smartmenus/bootstrap_cms.html', takes_context=True)
def smartmenu_bootstrap_cms(context, theme):
    context['theme'] = theme
    return context


text:
import ItemList from './utils/ItemList';
import Translator from './Translator';
import Store, { ApiPayload, ApiResponsePlural, ApiResponseSingle } from './Store';
import Session from './Session';
import Drawer from './utils/Drawer';
import RequestError, { InternalFlarumRequestOptions } from './utils/RequestError';
import Forum from './models/Forum';
import PageState from './states/PageState';
import ModalManagerState from './states/ModalManagerState';
import AlertManagerState from './states/AlertManagerState';
import type DefaultResolver from './resolvers/DefaultResolver';
import type Mithril from 'mithril';
import type Component from './Component';
import type { ComponentAttrs } from './Component';
import Model, { SavedModelData } from './Model';
export declare type FlarumScreens = 'phone' | 'tablet' | 'desktop' | 'desktop-hd';
export declare type FlarumGenericRoute = RouteItem<any, any, any>;
export interface FlarumRequestOptions<ResponseType> extends Omit<Mithril.RequestOptions<ResponseType>, 'extract'> {
    errorHandler?: (error: RequestError) => void;
    url: string;
    /**
     * Manipulate the response text before it is parsed into JSON.
     *
     * @deprecated Please use `modifyText` instead.
     */
    extract?: (responseText: string) => string;
    /**
     * Manipulate the response text before it is parsed into JSON.
     *
     * This overrides any `extract` method provided.
     */
    modifyText?: (responseText: string) => string;
}
/**
 * A valid route definition.
 */
export declare type RouteItem<Attrs extends ComponentAttrs, Comp extends Component<Attrs & {
    routeName: string;
}>, RouteArgs extends Record<string, unknown> = {}> = {
    /**
     * The path for your route.
     *
     * This might be a specific URL path (e.g.,`/myPage`), or it might
     * contain a variable used by a resolver (e.g., `/myPage/:id`).
     *
     * @see https://docs.flarum.org/extend/frontend-pages.html#route-resolvers-advanced
     */
    path: `/${string}`;
} & ({
    /**
     * The component to render when this route matches.
     */
    component: new () => Comp;
    /**
     * A custom resolver class.
     *
     * This should be the class itself, and **not** an instance of the
     * class.
     */
    resolverClass?: new (component: new () => Comp, routeName: string) => DefaultResolver<Attrs, Comp, RouteArgs>;
} | {
    /**
     * An instance of a route resolver.
     */
    resolver: RouteResolver<Attrs, Comp, RouteArgs>;
});
export interface RouteResolver<Attrs extends ComponentAttrs, Comp extends Component<Attrs & {
    routeName: string;
}>, RouteArgs extends Record<string, unknown> = {}> {
    /**
     * A method which selects which component to render based on
     * conditional logic.
     *
     * Returns the component class, and **not** a Vnode or JSX
     * expression.
     *
     * @see https://mithril.js.org/route.html#routeresolveronmatch
     */
    onmatch(this: this, args: RouteArgs, requestedPath: string, route: string): {
        new (): Comp;
    };
    /**
     * A function which renders the provided component.
     *
     * If not specified, the route will default to rendering the
     * component on its own, inside of a fragment.
     *
     * Returns a Mithril Vnode or other children.
     *
     * @see https://mithril.js.org/route.html#routeresolverrender
     */
    render?(this: this, vnode: Mithril.Vnode<Attrs, Comp>): Mithril.Children;
}
/**
 * The `App` class provides a container for an application, as well as various
 * utilities for the rest of the app to use.
 */
export default class Application {
    /**
     * The forum model for this application.
     */
    forum: Forum;
    /**
     * A map of routes, keyed by a unique route name. Each route is an object
     * containing the following properties:
     *
     * - `path` The path that the route is accessed at.
     * - `component` The Mithril component to render when this route is active.
     *
     * @example
     * app.routes.discussion = { path: '/d/:id', component: DiscussionPage };
     */
    routes: Record<string, FlarumGenericRoute>;
    /**
     * An ordered list of initializers to bootstrap the application.
     */
    initializers: ItemList<(app: this) => void>;
    /**
     * The app's session.
     *
     * Stores info about the current user.
     */
    session: Session;
    /**
     * The app's translator.
     */
    translator: Translator;
    /**
     * The app's data store.
     */
    store: Store;
    /**
     * A local cache that can be used to store data at the application level, so
     * that is persists between different routes.
     */
    cache: Record<string, unknown>;
    /**
     * Whether or not the app has been booted.
     */
    booted: boolean;
    /**
     * The page the app is currently on.
     *
     * This object holds information about the type of page we are currently
     * visiting, and sometimes additional arbitrary page state that may be
     * relevant to lower-level components.
     */
    current: PageState;
    /**
     * The page the app was on before the current page.
     *
     * Once the application navigates to another page, the object previously
     * assigned to this.current will be moved to this.previous, while this.current
     * is re-initialized.
     */
    previous: PageState;
    /**
     * An object that manages modal state.
     */
    modal: ModalManagerState;
    /**
     * An object that manages the state of active alerts.
     */
    alerts: AlertManagerState;
    /**
     * An object that manages the state of the navigation drawer.
     */
    drawer: Drawer;
    data: {
        apiDocument: ApiPayload | null;
        locale: string;
        locales: Record<string, string>;
        resources: SavedModelData[];
        session: {
            userId: number;
            csrfToken: string;
        };
        [key: string]: unknown;
    };
    private _title;
    private _titleCount;
    private set title(value);
    get title(): string;
    private set titleCount(value);
    get titleCount(): number;
    /**
     * The key for an Alert that was shown as a result of an AJAX request error.
     * If present, it will be dismissed on the next successful request.
     */
    private requestErrorAlert;
    initialRoute: string;
    load(payload: Application['data']): void;
    boot(): void;
    bootExtensions(extensions: Record<string, {
        extend?: unknown[];
    }>): void;
    protected mount(basePath?: string): void;
    /**
     * Get the API response document that has been preloaded into the application.
     */
    preloadedApiDocument<M extends Model>(): ApiResponseSingle<M> | null;
    preloadedApiDocument<Ms extends Model[]>(): ApiResponsePlural<Ms[number]> | null;
    /**
     * Determine the current screen mode, based on our media queries.
     */
    screen(): FlarumScreens;
    /**
     * Set the `<title>` of the page.
     *
     * @param title New page title
     */
    setTitle(title: string): void;
    /**
     * Set a number to display in the `<title>` of the page.
     *
     * @param count Number to display in title
     */
    setTitleCount(count: number): void;
    updateTitle(): void;
    protected transformRequestOptions<ResponseType>(flarumOptions: FlarumRequestOptions<ResponseType>): InternalFlarumRequestOptions<ResponseType>;
    /**
     * Make an AJAX request, handling any low-level errors that may occur.
     *
     * @see https://mithril.js.org/request.html
     */
    request<ResponseType>(originalOptions: FlarumRequestOptions<ResponseType>): Promise<ResponseType>;
    /**
     * By default, show an error alert, and log the error to the console.
     */
    protected requestErrorCatch<ResponseType>(error: RequestError, customErrorHandler: FlarumRequestOptions<ResponseType>['errorHandler']): Promise<never>;
    protected requestErrorDefaultHandler(e: unknown, isDebug: boolean, formattedErrors: string[]): void;
    private showDebug;
    /**
     * Construct a URL to the route with the given name.
     */
    route(name: string, params?: Record<string, unknown>): string;
}


text:
import renderer from "react-test-renderer";
import Err, {
  StepOneAction,
  AdditionalMessage,
  ContactLink,
  ContactUs,
} from "../Err";

describe("StepOneAction", () => {
  const defaultProps = {
    goToStepOne: jest.fn(),
  };
  const generateComponent = (additionalProps = {}) => {
    const newProps = {
      ...defaultProps,
      ...additionalProps,
    };
    return <StepOneAction { ...newProps } />;
  };

  it("renders if step one function", () => {
    const result = renderer.create(generateComponent());
    expect(result).toMatchSnapshot();
  });

  it("does not render if no step one function", () => {
    const result = renderer.create(generateComponent({
      goToStepOne: null,
    }));
    expect(result).toMatchSnapshot();
  });
});

describe("AdditionalMessage", () => {
  const defaultProps = {
    additionalMessage: "message",
  };
  const generateComponent = (additionalProps = {}) => {
    const newProps = {
      ...defaultProps,
      ...additionalProps,
    };
    return <AdditionalMessage { ...newProps } />;
  };

  it("renders if additional message", () => {
    const result = renderer.create(generateComponent());
    expect(result).toMatchSnapshot();
  });

  it("does not render if no additional message", () => {
    const result = renderer.create(generateComponent({
      additionalMessage: null,
    }));
    expect(result).toMatchSnapshot();
  });
});

describe("ContactLink", () => {
  const defaultProps = {};
  const generateComponent = (additionalProps = {}) => {
    const newProps = {
      ...defaultProps,
      ...additionalProps,
    };
    return <ContactLink { ...newProps } />;
  };

  it("renders", () => {
    const result = renderer.create(generateComponent());
    expect(result).toMatchSnapshot();
  });
});

describe("ContactUs", () => {
  const defaultProps = {};
  const generateComponent = (additionalProps = {}) => {
    const newProps = {
      ...defaultProps,
      ...additionalProps,
    };
    return <ContactUs { ...newProps } />;
  };

  it("renders", () => {
    const result = renderer.create(generateComponent());
    expect(result).toMatchSnapshot();
  });
});

describe("Err", () => {
  const defaultProps = {
    msg: "error",
    goToStepOne: jest.fn(),
    additionalMessage: "additional",
  };
  const generateComponent = (additionalProps = {}) => {
    const newProps = {
      ...defaultProps,
      ...additionalProps,
    };
    return <Err { ...newProps } />;
  };

  it("renders", () => {
    const result = renderer.create(generateComponent());
    expect(result).toMatchSnapshot();
  });
});