https://github.com/niny9/InternDataSpider)
---

## 🚀 项目简介
本项目是一个**面向特定实习信息的分布式爬虫系统**，专注于抓取并整合主流招聘平台（牛客网、Boss直聘、小红书）的实习、校招、社招信息。通过动态反爬策略、多源异构数据解析、弹性存储架构，实现高效数据采集与实时检索，帮助用户快速获取精准岗位信息！

**核心功能亮点**：
- 🔥 分布式爬虫：基于Scrapy-Redis实现高并发任务调度
- 🛡 智能反爬：动态IP池、UA轮换、Selenium模拟操作
- 📊 混合存储：MySQL + Elasticsearch + Logstash增量同步
- 📈 实时监控：Prometheus + Grafana可视化运维
- 🖥 交互界面：Bootstrap动态表单 + RESTful API

---

## 🛠 技术栈
| 模块                | 技术组件                                                                 |
|---------------------|--------------------------------------------------------------------------|
| **爬虫框架**         | Scrapy、Selenium、DrissionPage                                          |
| **分布式调度**       | Redis Streams、RabbitMQ                                                 |
| **数据存储**         | MySQL、Elasticsearch、Logstash                                         |
| **运维监控**         | Prometheus、Grafana、Loki                                              |
| **前端交互**         | HTML/CSS/JS、Bootstrap、jQuery                                         |
| **部署工具**         | Docker、Kubernetes                                                      |

---

## 📂 代码框架
```bash
InternDataSpider/
├── crawlers/
│   ├── zhipin_spider/           # Boss直聘爬虫（反爬策略+动态渲染）
│   ├── xiaohongshu_spider1/     # 小红书笔记爬虫（异步接口监听）
│   └── nowcode_one/             # 牛客网爬虫（标准化页面解析）
│
├── storage-docker/              # 存储服务Docker配置（MySQL+ES+Logstash）
├── monitor/                     # Prometheus监控配置 + Grafana仪表盘
├── frontend/                    # 前端交互页面（Bootstrap动态表单）
│
├── scripts/
│   ├── 推送脚本.py              # URL去重与Redis任务分发
│   ├── 小红书测试脚本.py        # 小红书反爬模拟测试
│   └── 所有网址.txt            # 初始爬取URL集合
│
├── requirements.txt            #


local event = GEM_Events.realms[GEM_Realm].events[ev_id];

  if(event == nil) -- Event does not exist anymore
  then
    return "Event "..ev_id.." does not exist anymore";
  end
  if(GEM_IsMyReroll(event.leader)) -- I'm the leader
  then
    return "Cannot re-subscribe my own event";
  end
  if(GEM_Events.realms[GEM_Realm].banned[ev_id] ~= nil)
  then
    GEM_ChatPrint("I am banned from EventID "..ev_id.." : "..GEM_Events.realms[GEM_Realm].banned[ev_id]);
    return "I'm banned from Event "..ev_id.." : "..GEM_Events.realms[GEM_Realm].banned[ev_id];
  end

  if(GEM_Events.realms[GEM_Realm].subscribed[ev_id] ~= nil)
  then
    GEM_ChatDebug(GEM_DEBUG_GLOBAL,"GEM_COM_Subscribe : Already tagged for subscription !!");
    return "Internal error : Already tagged for subscription";
  end

  _GEM_COM_PrepareAndSendCommand(ev_id,GEM_CMD_CMD_SUBSCRIBE,event.leader,selected,infos.class,infos.guild,infos.level,forcesub,comment);

  GEM_EVT_SubscribeMyself(ev_id,selected,infos.class,infos.level,infos.class,comment,forcesub,"0"); -- Tag myself as having sent a subscription
  GEM_NotifyGUI(GEM_NOTIFY_MY_SUBSCRIPTION,ev_id);

  return nil;
end

--[[ - GUI ENTRY POINT
 function GEM_COM_Unsubscribe :
  Unsubscribes from an event and broadcast it (Sent by player, once).
   ev_id : String -- Event ID to unsubscribe from
   comment  : String -- Comment to send with unsubscription
]]
function GEM_COM_Unsubscribe(ev_id,comment)
  local event = GEM_Events.realms[GEM_Realm].events[ev_id];

  if(event == nil) -- Event does not exist anymore
  then
    return;
  end
  if(GEM_IsMyReroll(event.leader)) -- Cannot remove ourself
  then
    GEM_ChatPrint("GEM_COM_Unsubscribe : Cannot unsubscribe from your own event !");
    return;
  end

  if(GEM_Events.realms[GEM_Realm].subscribed[ev_id] == nil)
  then
    GEM_ChatDebug(GEM_DEBUG_GLOBAL,"GEM_COM_Unsubscribe : I'm not tagged as having sent subscription !!");
    return;
  end

  _GEM_COM_PrepareAndSendCommand(ev_id,GEM_CMD_CMD_UNSUBSCRIBE,event.leader,GEM_Events.realms[GEM_Realm].subscribed[ev_id].name,comment);

  GEM_Events.realms[GEM_Realm].subscribed[ev_id] = nil;
  GEM_Events.realms[GEM_Realm].assistant[ev_id] = nil; -- Reset assistant status
  GEM_NotifyGUI(GEM_NOTIFY_MY_SUBSCRIPTION,ev_id);
end

--[[ - GUI ENTRY POINT
 function GEM_COM_TitularPlayer :
  Informs a player he is titular, from an event I'm the leader.
   ev_id   : String -- Event ID
   pl_name : String -- Player to inform
]]
function GEM_COM_TitularPlayer(ev_id,pl_name)
  local event = GEM_Events.realms[GEM_Realm].events[ev_id];

  if(event ~= nil)
  then
    if(not GEM_IsMyReroll(event.leader))
    then
      GEM_ChatPrint("GEM_COM_TitularPlayer : This E


s using slice
    vector <size_t> a4_begin(%input.rank), a4_size(%input.rank)

    for (int32 i = 0; i < %input.rank; i++) {
        if (i == 0 || i > crop_dims) {
           a4_begin[i] = 0
           a4_size[i] = output_shape[i]
        } else {
          a4_begin[i] = %crops[i-1].first
          a4_size[i] = crops[i - 1].first - crops[i - 1].second
        }
    }

    %a1_reshape = tosa.RESHAPE(%input) {new_shape=a1_shape}
    %a2_transpose = tosa.TRANSPOSE(%a1_reshape) {perms=a2_perm}
    %a3_reshape = tosa.RESHAPE(%a2_transpose) {new_shape=a3_shape}
    %output = tosa.SLICE(%a3_reshape) {begin=a4_begin, size=a4_size}

    return %output
}
```

### lower_concatv2_op()

```
Value lower_concatv2_op(Type output_type, Value %values, int32 axis)
{
    int32 tosa_axis = positive_axis(axis)

    assert(%values.size >= 2)

    // Convert scalar inputs to a tensor
    if (%values:0.size == 0) {
       for (int32 i = 0; i < %values.size; i++) {
          %values:i = tosa.RESHAPE(%values:i) {new_shape=1}
       }
    }

    for (int32 i=0; i < %values.size(); i++) {
        %val = %values:i
        if (%val.zp != output_type.zp || %val.scale != output_type.scale) {
            float64 rescale_scale = %val.scale / output_type.scale
            %values:i = tosa.RESCALE(%val) {scale=rescale_scale, input_zp=%values:0.zp, output_zp=output_type.zp}
        }
    }

    %concat_op = tosa.CONCAT(%values:0, %values:1) {axis=tosa_axis}

    for (int32 i = 2; i < %values.size; i++) {
        %concat_op = tosa.CONCAT(%concat_op, %values:i) {axis=tosa_axis}
    }

    return %concat_op
}
```

### lower_depth_to_space_op()

```
Value lower_depth_to_space_op(Value %input, size_t block_size[], Format_t data_format)
{
    assert(data_format == 'NHWC')

    vector <size_t> a2_shape = {%input.shape[0],
                                %input.shape[1],
                                %input.shape[2],
                                block_size[0],
                                block_size[1],
                                %input.shape[3] / (block_size[0] * block_size[1])}

    vector <size_t> a4_shape = {%input.shape[0],
                                %input.shape[1] * block_size[0],
                                %input.shape[2] * block_size[1],
                                %input.shape[3] / (block_size[0] * block_size[1])}

    %a2_reshape = tosa.RESHAPE(%input) {new_shape=a2_shape}
    %a3_transpose = tosa.TRANSPOSE(%a2_reshape) {perms={0, 1, 3, 2, 4, 5}}
    %output = tosa.RESHAPE(%a3_transpose) {new_shape=a4_shape}

    return %output
}
```

### lower_elu_op()

```
Value lower_


tp = Shunt(OP1)

        for m, arg in enumerate(args):

            if m & 1:
                self.tp = self.tp.chain(Shunt(arg))
            else:
                self.tp = self.tp.chain(Series(arg))

        super(LadderAlt, self).__init__(self.tp)
        self.args = (OP1, ) + args

    def simplify(self):

        if len(self.args) == 1:
            return Shunt(self.args[0])
        elif len(self.args) == 2:
            return LSectionAlt(*self.args)
        elif len(self.args) == 3:
            return PiSection(*self.args)
        return self

        # A Ladder of voltage sources and current sources
        # collapses to a single Lsection comprised of the total
        # voltage and total current.

class GeneralTransmissionLine(TwoPortThing):
    """General transmission line

    Z0    characteristic impedance (ohms)
    gamma propagation constant (1/m)
    l     transmission line length (m)
    """

    reactive = True

    def __init__(self, Z0='Z0(s)', gamma='gamma(s)', l='l'):

        Z0 = LaplaceDomainExpression(Z0)
        gamma = LaplaceDomainExpression(gamma)
        l = ConstantDomainExpression(l)

        H = exp(gamma * l).expr

        B11 = sym.S.Half * (H + 1 / H)
        B12 = sym.S.Half * (1 / H - H) * Z0
        B21 = sym.S.Half * (1 / H - H) / Z0
        B22 = sym.S.Half * (H + 1 / H)

        B = BMatrix(((B11, B12), (B21, B22))).simplify()

        super(GeneralTransmissionLine, self).__init__(B)
        self.Z0 = Z0
        self.gamma = gamma
        self.l = l
        self.args = (Z0, gamma, l)

class GeneralTxLine(GeneralTransmissionLine):
    pass

class TL(GeneralTransmissionLine):
    """General transmission line"""

    # This class is used for netlists.
    pass

class LosslessTransmissionLine(GeneralTransmissionLine):
    """Lossless transmission line
        Z0 (real) characteristic impedance (ohms)
        c  propagation speed (m/s)
        l  transmission line length (m)
        """

    def __init__(self, Z0='Z0', c='c', l='l'):

        gamma = s / c

        super(LosslessTransmissionLine, self).__init__(Z0, gamma, l)
        self.args = (Z0, c, l)

class LosslessTxLine(LosslessTransmissionLine):
    pass

class TLlossless(LosslessTransmissionLine):
    """Lossless transmission line"""

    # This class is used for netlists.
    pass

class TransmissionLine(GeneralTransmissionLine):
    """Transmission line

    R series resistance/unit length
    L series inductance/unit length
    G shunt conductance/unit length
    C shunt capacitance/unit length
    l transmission line length
    """

    def __init__(self, R='R', L='L', G='G', C='C', l='l'):

        Z = R + s * L
        Y = G + s * C
        gamma = sqrt(Z * Y).expr
        Z0 = sqrt(Z / Y).expr

        super(TransmissionLine, self).__init__(Z0, gamma, l)
        self.args = (R, L, G, C, l)

class TxLine(TransmissionLine):
    pass


ng
};
var PageItem_defaultProps = {
  active: false,
  disabled: false,
  activeLabel: '(current)'
};
function PageItem(_ref) {
  var active = _ref.active,
      disabled = _ref.disabled,
      className = _ref.className,
      style = _ref.style,
      activeLabel = _ref.activeLabel,
      children = _ref.children,
      props = _objectWithoutPropertiesLoose(_ref, ["active", "disabled", "className", "style", "activeLabel", "children"]);

  var Component = active || disabled ? 'span' : src_SafeAnchor;
  return external_root_React_commonjs2_react_commonjs_react_amd_react_default.a.createElement("li", {
    style: style,
    className: classnames_default()(className, 'page-item', {
      active: active,
      disabled: disabled
    }),
    __source: {
      fileName: PageItem_jsxFileName,
      lineNumber: 36
    },
    __self: this
  }, external_root_React_commonjs2_react_commonjs_react_amd_react_default.a.createElement(Component, _extends({
    className: "page-link",
    disabled: disabled
  }, props, {
    __source: {
      fileName: PageItem_jsxFileName,
      lineNumber: 40
    },
    __self: this
  }), children, active && activeLabel && external_root_React_commonjs2_react_commonjs_react_amd_react_default.a.createElement("span", {
    className: "sr-only",
    __source: {
      fileName: PageItem_jsxFileName,
      lineNumber: 43
    },
    __self: this
  }, activeLabel)));
}
PageItem.propTypes = PageItem_propTypes;
PageItem.defaultProps = PageItem_defaultProps;

function createButton(name, defaultValue, label) {
  var _class, _temp;

  if (label === void 0) {
    label = name;
  }

  return _temp = _class =
  /*#__PURE__*/
  function (_React$Component) {
    _inheritsLoose(_class, _React$Component);

    function _class() {
      return _React$Component.apply(this, arguments) || this;
    }

    var _proto = _class.prototype;

    _proto.render = function render() {
      var _this$props = this.props,
          children = _this$props.children,
          props = _objectWithoutPropertiesLoose(_this$props, ["children"]);

      delete props.active;
      return external_root_React_commonjs2_react_commonjs_react_amd_react_default.a.createElement(PageItem, _extends({}, props, {
        __source: {
          fileName: PageItem_jsxFileName,
          lineNumber: 61
        },
        __self: this
      }), external_root_React_commonjs2_react_commonjs_react_amd_react_default.a.createElement("span", {
        "aria-hidden": "true",
        __source: {
          fileName: PageItem_jsxFileName,
          lineNumber: 62
        },
        __self: this
      }, children || defaultValue), external_root_React_commonjs2_react_commonjs_react_amd_react_default.a.createElement("span", {
        className: "sr-only",
        __source: {
          fileName: PageItem_jsxFileName,
          lineNumber: 63
        },
        __self: this
      }, label));
    };

    return _class;
  }(external_root_React_commonjs2_react_commonjs_react_amd_react_default.a.Component), _class.displayName = name, _temp;
}

var First = createButton('First', "\xAB");
var Prev = createButton('Prev', "\u2039", 'Previous');
var Ellipsis = createButton('Ellipsis', "\u2026", 'More');
var Next = create


arena) {
  SharedCtor();
  RegisterArenaDtor(arena);
  // @@protoc_insertion_point(arena_constructor:attestation_user_data)
}
attestation_user_data::attestation_user_data(const attestation_user_data& from)
  : ::PROTOBUF_NAMESPACE_ID::Message(),
    _has_bits_(from._has_bits_) {
  _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
  enclave_type_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
  if (from._internal_has_enclave_type()) {
    enclave_type_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_enclave_type(),
                      GetArena());
  }
  time_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
  if (from._internal_has_time()) {
    time_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_time(),
              GetArena());
  }
  if (from._internal_has_enclave_key()) {
    enclave_key_ = new ::key_message(*from.enclave_key_);
  } else {
    enclave_key_ = nullptr;
  }
  if (from._internal_has_policy_key()) {
    policy_key_ = new ::key_message(*from.policy_key_);
  } else {
    policy_key_ = nullptr;
  }
  // @@protoc_insertion_point(copy_constructor:attestation_user_data)
}

void attestation_user_data::SharedCtor() {
  ::PROTOBUF_NAMESPACE_ID::internal::InitSCC(&scc_info_attestation_user_data_certifier_2eproto.base);
  enclave_type_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
  time_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
  ::memset(&enclave_key_, 0, static_cast<size_t>(
             reinterpret_cast<char*>(&policy_key_) -
             reinterpret_cast<char*>(&enclave_key_)) + sizeof(policy_key_));
}

attestation_user_data::~attestation_user_data() {
  // @@protoc_insertion_point(destructor:attestation_user_data)
  SharedDtor();
  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
}

void attestation_user_data::SharedDtor() {
  GOOGLE_DCHECK(GetArena() == nullptr);
  enclave_type_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
  time_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
  if (this != internal_default_instance()) delete enclave_key_;
  if (this != internal_default_instance()) delete policy_key_;
}

void attestation_user_data::ArenaDtor(void* object) {
  attestation_user_data* _this = reinterpret_cast< attestation_user_data* >(object);
  (void)_this;
}
void attestation_user_data::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
}
void attestation_user_data::SetCachedSize(int size) const {
  _cached_size_.Set(size);
}
const attestation_user_data& attestation_user_data::default_instance() {
  ::PROTOBUF_NAMESPACE_ID::internal::InitSCC(&::scc_info_at


 {
		"id": "github",
		"name": "Github",
		"colors": {
			"node_slot": {
			  "BOOLEAN": "",
			  "CLIP": "#eacb8b",
			  "CLIP_VISION": "#A8DADC",
			  "CLIP_VISION_OUTPUT": "#ad7452",
			  "CONDITIONING": "#cf876f",
			  "CONTROL_NET": "#00d78d",
			  "CONTROL_NET_WEIGHTS": "",
			  "FLOAT": "",
			  "GLIGEN": "",
			  "IMAGE": "#80a1c0",
			  "IMAGEUPLOAD": "",
			  "INT": "",
			  "LATENT": "#b38ead",
			  "LATENT_KEYFRAME": "",
			  "MASK": "#a3bd8d",
			  "MODEL": "#8978a7",
			  "SAMPLER": "",
			  "SIGMAS": "",
			  "STRING": "",
			  "STYLE_MODEL": "#C2FFAE",
			  "T2I_ADAPTER_WEIGHTS": "",
			  "TAESD": "#DCC274",
			  "TIMESTEP_KEYFRAME": "",
			  "UPSCALE_MODEL": "",
			  "VAE": "#be616b"
			},
			"litegraph_base": {
			  "BACKGROUND_IMAGE": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAACXBIWXMAAAsTAAALEwEAmpwYAAAGlmlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4xLWMwMDEgNzkuMTQ2Mjg5OSwgMjAyMy8wNi8yNS0yMDowMTo1NSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0RXZ0PSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VFdmVudCMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIDI1LjEgKFdpbmRvd3MpIiB4bXA6Q3JlYXRlRGF0ZT0iMjAyMy0xMS0xM1QwMDoxODowMiswMTowMCIgeG1wOk1vZGlmeURhdGU9IjIwMjMtMTEtMTVUMDI6MDQ6NTkrMDE6MDAiIHhtcDpNZXRhZGF0YURhdGU9IjIwMjMtMTEt


button:0 0 0 var(--pico-outline-width) var(--pico-primary-focus);--pico-group-box-shadow-focus-with-input:0 0 0 0.0625rem var(--pico-form-element-border-color);--pico-modal-overlay-backdrop-filter:blur(0.375rem);--pico-nav-element-spacing-vertical:1rem;--pico-nav-element-spacing-horizontal:0.5rem;--pico-nav-link-spacing-vertical:0.5rem;--pico-nav-link-spacing-horizontal:0.5rem;--pico-nav-breadcrumb-divider:">";--pico-icon-checkbox:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");--pico-icon-minus:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='5' y1='12' x2='19' y2='12'%3E%3C/line%3E%3C/svg%3E");--pico-icon-chevron:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--pico-icon-date:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E");--pico-icon-time:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cpolyline points='12 6 12 12 16 14'%3E%3C/polyline%3E%3C/svg%3E");--pico-icon-search:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' vi


# Student ID: 2022-0076767
# Course: MATH6200 - Data Analysis
# Activity: Course Project (Week 13)
# Question: [B] Is there a significant difference in the level of sleep quality when they grouped according to sex?
# Formula: Statistical Test (ttest)

import pandas as pd
import os
from scipy import stats

def clear_terminal():
    # Check the operating system
    if os.name == 'nt':  # For Windows
        os.system('cls')
    else:  # For Linux and macOS
        os.system('clear')

def add_new_line():
    print("\n")

def get_data_frame():
    # Reading the absolute path of the file.
    course_project_data = os.path.join(os.path.dirname(__file__), 'files/course-project-data.csv')

    # Read the file into a data frame.
    # Return at the same time.
    return pd.read_csv(course_project_data)

def get_sleep_quality_column(data_frame: pd.DataFrame):
    return data_frame['Sleep Quality']

def get_sex_column(data_frame: pd.DataFrame):
    return data_frame['Sex']

def answer_b():
    # Clear the terminal first.
    clear_terminal()
    add_new_line()

    # Show the description on what to needs to be answered.
    print("\033[32m Is there a significant difference in the level of sleep quality when they grouped according to sex? \033[0m")
    print("-----------------------------------------------------------------------------------------------------")

    # Get the course project data frame.
    data_frame = get_data_frame()
    print(data_frame)
    add_new_line()

    # Get the sleep quality and gender column.
    sleep_quality_column = get_sleep_quality_column(data_frame)
    sex_column = get_sex_column(data_frame)

    # Separate sleep quality based on sex (males and females).
    female_sleep_quality = sleep_quality_column[sex_column == 'Female']
    male_sleep_quality = sleep_quality_column[sex_column == 'Male']

    # Perform t-test to check for a significant difference.
    t_stat, p_value = stats.ttest_ind(female_sleep_quality, male_sleep_quality)

    # Display the result.
    # Show the description on what to needs to be answered.
    print("\033[32m Calculation Result \033[0m")
    print("--------------------------------")
    print("T-statistic: ", t_stat)
    print("P-value: ", p_value)
    add_new_line()

    # Conclusion
    print("\033[32m Conclusion \033[0m")
    print("---------------------------------------------------")
    print("Here, a T-statistic of 2.7778 indicates that the \ndifference in sleep quality between females and \nmales is significant in the context of the \nvariability of the data.")
    add_new_line()
    print("A P-value of 0.0097 is very small, much lower \nthan the common significance threshold of 0.05. \nThis suggests that there is a statistically \nsignificant difference between the sleep \nquality of females and males.")
    add_new_line()
    print("This result means that the data provides strong \nevidence that the average sleep quality is \ndifferent for females and males.")
    add_new_line()
    add_new_line()

answer_b()


(1), 请求.AppData.AppName, "", "防误操作应用"+strconv.Itoa(局_旧AppInfo.AppId)+"更换私钥旧私钥:"+局_旧AppInfo.CryptoKeyPrivate, c.ClientIP())
	}
	//=====网页用户中心配置============
	tx := *global.GVA_DB
	_, err = service.NewAppInfoWebUser(c, &tx).Info(局_旧AppInfo.AppId)
	if err != nil {
		_, err = service.NewAppInfoWebUser(c, &tx).Create(dbm.DB_AppInfoWebUser{
			Id:             局_旧AppInfo.AppId,
			Status:         请求.AppInfoWebUser.Status,
			CaptchaLogin:   请求.AppInfoWebUser.CaptchaLogin,
			UrlDownload:    请求.AppInfoWebUser.UrlDownload,
			CaptchaReg:     请求.AppInfoWebUser.CaptchaReg,
			CaptchaSendSms: 请求.AppInfoWebUser.CaptchaSendSms,
			WebUserDomain:  请求.AppInfoWebUser.WebUserDomain,
		})
	} else {
		_, err = service.NewAppInfoWebUser(c, &tx).Update(局_旧AppInfo.AppId, map[string]interface{}{
			"status":         请求.AppInfoWebUser.Status,
			"captchaLogin":   请求.AppInfoWebUser.CaptchaLogin,
			"urlDownload":    请求.AppInfoWebUser.UrlDownload,
			"captchaReg":     请求.AppInfoWebUser.CaptchaReg,
			"captchaSendSms": 请求.AppInfoWebUser.CaptchaSendSms,
			"webUserDomain":  请求.AppInfoWebUser.WebUserDomain,
		})
	}
	if err != nil {
		response.FailWithMessage("保存网页用户中心配置失败", c)
		return
	}
	//===========检查专属变量
	for _, 专属变量 := range 请求.PublicData {
		局_临时, err2 := publicData.L_publicData.Q取值2(c, 专属变量.AppId, 专属变量.Name)
		if err2 != nil {
			continue
		}
		if 局_临时.Value != 专属变量.Value || 局_临时.IsVip != 专属变量.IsVip || 局_临时.Note != 专属变量.Note || 局_临时.Type != 专属变量.Type || 局_临时.Sort != 专属变量.Sort {
			//只有值改变了才修改时间戳
			if 局_临时.Value != 专属变量.Value {
				专属变量.Time = time.Now().Unix()
			}

			_ = publicData.L_publicData.Z置值_原值(c, 专属变量)
		}
	}

	//================检查apihook函数
	JSON, err := fastjson.Parse(请求.AppData.ApiHook)
	if err == nil {
		if object, err2 := JSON.Object(); err2 == nil {
			//JSON取全部成员
			object.Visit(func(key []byte, v *fastjson.Value) {
				// 获取所有键名
				//{"UserLogin":{"Before":"hook登录前","After":"hook登录后"}}
				局_hook函数名 := strings.TrimSpace(string(v.GetStringBytes("Before")))
				if len(局_hook函数名) > 0 && !


glabel func_808DC66C
/* 05DFC 808DC66C 27BDFFE0 */  addiu   $sp, $sp, 0xFFE0           ## $sp = FFFFFFE0
/* 05E00 808DC670 AFBF001C */  sw      $ra, 0x001C($sp)
/* 05E04 808DC674 AFB00018 */  sw      $s0, 0x0018($sp)
/* 05E08 808DC678 00808025 */  or      $s0, $a0, $zero            ## $s0 = 00000000
/* 05E0C 808DC67C 0C235C4B */  jal     func_808D712C
/* 05E10 808DC680 2406017C */  addiu   $a2, $zero, 0x017C         ## $a2 = 0000017C
/* 05E14 808DC684 3C040601 */  lui     $a0, 0x0601                ## $a0 = 06010000
/* 05E18 808DC688 0C028800 */  jal     SkelAnime_GetFrameCount

/* 05E1C 808DC68C 24848128 */  addiu   $a0, $a0, 0x8128           ## $a0 = 06008128
/* 05E20 808DC690 44822000 */  mtc1    $v0, $f4                   ## $f4 = 0.00
/* 05E24 808DC694 3C050601 */  lui     $a1, 0x0601                ## $a1 = 06010000
/* 05E28 808DC698 24A58128 */  addiu   $a1, $a1, 0x8128           ## $a1 = 06008128
/* 05E2C 808DC69C 468021A0 */  cvt.s.w $f6, $f4
/* 05E30 808DC6A0 26040150 */  addiu   $a0, $s0, 0x0150           ## $a0 = 00000150
/* 05E34 808DC6A4 24060000 */  addiu   $a2, $zero, 0x0000         ## $a2 = 00000000
/* 05E38 808DC6A8 0C029490 */  jal     func_800A5240
/* 05E3C 808DC6AC E60601CC */  swc1    $f6, 0x01CC($s0)           ## 000001CC
/* 05E40 808DC6B0 3C048090 */  lui     $a0, %hi(D_808F93C0)       ## $a0 = 80900000
/* 05E44 808DC6B4 240E0046 */  addiu   $t6, $zero, 0x0046         ## $t6 = 00000046
/* 05E48 808DC6B8 248493C0 */  addiu   $a0, $a0, %lo(D_808F93C0)  ## $a0 = 808F93C0
/* 05E4C 808DC6BC A60E01B6 */  sh      $t6, 0x01B6($s0)           ## 000001B6
/* 05E50 808DC6C0 8C8F0000 */  lw      $t7, 0x0000($a0)           ## 808F93C0
/* 05E54 808DC6C4 44804000 */  mtc1    $zero, $f8                 ## $f8 = 0.00
/* 05E58 808DC6C8 3C0B808E */  lui     $t3, %hi(func_808DC75C)    ## $t3 = 808E0000
/* 05E5C 808DC6CC 44800000 */  mtc1    $zero, $f0                 ## $f0 = 0.00
/* 05E60 808DC6D0 E5E816C0 */  swc1    $f8, 0x16C0($t7)           ## 000016C0
/* 05E64 808DC6D4 8C830000 */  lw      $v1, 0x0000(


// <copyright>
// Copyright by the Spark Development Network
//
// Licensed under the Rock Community License (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.rockrms.com/license
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
//
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;
using System.Runtime.Serialization;

using Rock.Data;

namespace Rock.Model
{
    /// <summary>
    ///
    /// </summary>
    [RockDomain( "CMS" )]
    [Table( "ContentChannelItemSlug" )]
    [DataContract]
    [CodeGenerateRest]
    [Rock.SystemGuid.EntityTypeGuid( "2FF2F1C3-A440-4D24-8FB8-2B0D9436EA75")]
    public partial class ContentChannelItemSlug : Model<ContentChannelItemSlug>
    {
        #region Entity Properties

        /// <summary>
        /// Gets or sets the <see cref="Rock.Model.ContentChannelItem"/> identifier.
        /// </summary>
        /// <value>
        /// The content channel item identifier.
        /// </value>
        [Required]
        [DataMember( IsRequired = true )]
        [IgnoreCanDelete]
        public int ContentChannelItemId { get; set; }

        /// <summary>
        /// Gets or sets the slug.
        /// </summary>
        /// <value>
        /// The slug.
        /// </value>
        [MaxLength( 200 )]
        [DataMember]
        public string Slug { get; set; }


1).Magnitude());
        fArcLenDeltas[cnt++]=aldi;

        time += timeInc;
        p1 = p2;
    }
    hsAssert((int32_t)fArcLenDeltas.size() == numSamples, "arcLenArray size wrong?");
    hsAssert(cnt==numSamples, "arcLenArray size wrong?");
}

//
// Returns time of point (at least) arcLength units away from point at startTime.
// Also sets strtSrchIdx for incremental searching.
//
float plAnimPath::GetLookAheadTime(float startTime, float arcLengthIn, bool bwd,
                                      int32_t* startSrchIdx)
{
    if (arcLengthIn==0)
        return startTime;   // default is no look ahead

    if (startTime==GetLength() && !bwd)
        return GetLength();

    if (startTime==0 && bwd)
        return 0;

    hsAssert(startSrchIdx, "nil var for startSrchIdx");

    float oldTime=fTime;

    ComputeArcLenDeltas();  // precompute first time only

    // save and change time if necessary
    if (fTime!=startTime)
        SetCurTime(startTime, kCalcPosOnly);

    // find nearest (forward) arcLen sample point, use starting srch index provided
    bool found=false;
    for (int32_t i = (*startSrchIdx); i < (int32_t)fArcLenDeltas.size()-1; i++)
    {
        if (fArcLenDeltas[i].fT<=startTime && startTime<fArcLenDeltas[i+1].fT)
        {
            *startSrchIdx=i;
            found=true;
            break;
        }
    }

    if (!found)
    {
        // check if equal to last index
        if (startTime == fArcLenDeltas.back().fT)
        {
            *startSrchIdx = (int32_t)fArcLenDeltas.size() - 1;
            found=true;
        }
        else
        {
            for (int32_t i = 0; i < *startSrchIdx; i++)
            {
                if (fArcLenDeltas[i].fT<=startTime && startTime<fArcLenDeltas[i+1].fT)
                {
                    *startSrchIdx=i;
                    found=true;
                    break;
                }
            }
        }
    }

    // find distance to nearest arcLen sample point
    int32_t nearestIdx = bwd ? *startSrchIdx : *startSrchIdx+1;
    hsAssert(found, "couldn't find arcLength sample");

    hsPoint3 pos;
    GetPosition(&pos);      // startTime position

    hsPoint3 pos2;
    float endTime = fArcLenDeltas[nearestIdx].fT;
    SetCurTime(endTime, kCalcPosOnly);
    GetPosition(&pos2);     // position at nearest sample point

    float curArcLen = hsVector3(&pos2, &pos).Magnitude();
    float curTime=0;
    bool quit=false;
    float timeOut = 0;
    int32_t inc = bwd ? -1 : 1;
    // now sum distance deltas until we exceed the desired arcLen
    if (curArcLen<arcLengthIn)
    {
        int32_t i = bwd ? nearestIdx : nearestIdx+inc;
        for (; i < (int32_t)fArcLenDeltas.size() && i >= 0; i += inc)
        {
            if (curArcLen+fArcLenDeltas[i].fArcLenDelta>arcLengthIn)
            {
                // gone tooFar
                endTime = fArcLenDeltas[i].fT;
                curTime = fArcLenDeltas[i-1].fT;
                break;
            }
            curArcLen += fArcLenDeltas[i].fArcLenDelta;
        }

        if ((i == (int32_t)fArcLenDeltas.size() && !bwd) || (i < 0 && bwd))
        {
            quit=true;
            timeOut = bwd ? 0 : GetLength();
        }
    }
    else
    {
        curArcLen = 0;
        curTime = st


n A333_rescale(in1, out1, in2, out2, x)

    if x < in1 then return out1 end
    if x > in2 then return out2 end
    return out1 + (out2 - out1) * (x - in1) / (in2 - in1)

end

---- EXTRA AUTOPILOT FUNCTIONS

function A333_autopilot()

	if simDR_vertical_mode == 4 or simDR_vertical_mode == 19 then
		vvi_fpa_timer_running = 0
		vvi_fpa_timer_count = 0
	end

	if vvi_fpa_timer_running == 0 then
		vvi_fpa_timer_count = 0
	elseif vvi_fpa_timer_running == 1 then
		vvi_fpa_timer_count = vvi_fpa_timer_count + SIM_PERIOD
	end

	if vvi_fpa_timer_count >= 45 then
		vvi_fpa_timer_running = 0
		vvi_fpa_timer_count = 0
		simDR_vvi_setting = 0
		simDR_fpa_setting = 0
	end

	if vvi_fpa_timer_running == 0 then
		if simDR_vertical_mode == 4 or simDR_vertical_mode == 19 then
			A333_VVI_window_open = 1
		elseif simDR_vertical_mode ~= 4 and simDR_vertical_mode ~= 19 then
			A333_VVI_window_open = 0
		end
	elseif vvi_fpa_timer_running == 1 then
		A333_VVI_window_open = 1
	end

	if hdg_timer_running == 0 then
		hdg_timer_count = 0
	elseif hdg_timer_running == 1 then
		hdg_timer_count = hdg_timer_count + SIM_PERIOD
	end

	if hdg_timer_count >= 15 then
		hdg_timer_running = 0
		hdg_timer_count = 0
	end

	if simDR_gpss_status == 0 then
		A333_hdg_window_open = 1
	elseif simDR_gpss_status >= 1 then
		if hdg_timer_running == 0 then
			A333_hdg_window_open = 0
		elseif hdg_timer_running == 1 then
			A333_hdg_window_open = 1
		end
	end

	if A333_hdg_window_open == 0 then
		simDR_hdg_setting = simDR_current_heading
	end

end

function A333_autothrust()

	if simDR_eng1_N2 >= 5 then
		if simDR_eng2_N2 >= 5 then
			single_engine_status = 0
		elseif simDR_eng2_N2 < 5 then
			single_engine_status = 1
		end
	elseif simDR_eng1_N2 < 5 then
		if simDR_eng2_N2 >= 5 then
			single_engine_status = 1
		elseif simDR_eng2_N2 < 5 then
			single_engine_status = 0
		end
	end

	if simDR_gear_on_ground == 1 then
		if single_engine_status == 0 then
			if simDR_fadec_mode_eng1 >= 2 and simDR_fadec_mode_eng2 >= 2 then
				if simDR_autothrottle_mode ~= 0 then
					simDR_autothrottle_mode	= 0
				end
			end
		elseif single_engine_status == 1 then
		end
	elseif simDR_gear_on_ground == 0 then
		if single_engine_status == 0 then
			if simDR_fadec_mode_eng1 >= 2 and simDR_fadec_mode_eng2 >= 2 then
				if simDR_autothrottle_mode ~= 0 then
					simDR_autothrottle_mode	= 0
				end
			end
		elseif single_engine_status == 1 then
			if simDR_fadec_mode_eng1 == 3 or simDR_fadec_mode_eng2 == 3 then
				if simDR_autothrottle_mode ~= 0 then
					simDR_autothrottle_mode	= 0
				end
			end
		end
	end

end

----- MONITOR AI FOR AUTO-BOARD CALL ----------------------------------------------------
function A333_autopilot_monitor_AI()

    if A333DR_init_autopilot_CD == 1 then
        A333_set_autopilot_all_modes()
        A333_set_autopilot_CD()
        A333DR_init_autopilot_CD = 2
    end

end

----- SET


id) {
			self.qualifications.remove(*pos);
		}
	}
}

impl<T, AccountId, Hash, Moment: Default, Balance: Default> GeneticAnalystServiceOwnerInfo<T>
	for GeneticAnalyst<AccountId, Hash, Moment, Balance>
where
	Hash: PartialEq + Eq,
	T: frame_system::Config<AccountId = AccountId>,
{
	fn get_id(&self) -> &AccountId {
		self.get_account_id()
	}
}

impl<T, AccountId, Hash, Moment: Default, Balance: Default> GeneticAnalystQualificationOwnerInfo<T>
	for GeneticAnalyst<AccountId, Hash, Moment, Balance>
where
	Hash: PartialEq + Eq,
	T: frame_system::Config<AccountId = AccountId>,
{
	fn get_owner_id(&self) -> &AccountId {
		self.get_account_id()
	}
}

/// The current storage version.
const STORAGE_VERSION: StorageVersion = StorageVersion::new(2);

#[frame_support::pallet]
pub mod pallet {
	use crate::{interface::GeneticAnalystInterface, GeneticAnalyst, GeneticAnalystInfo, *};
	use codec::EncodeLike;
	use frame_support::{dispatch::DispatchResultWithPostInfo, traits::Currency};
	use frame_system::pallet_prelude::*;
	pub use sp_std::prelude::*;
	pub use traits_genetic_analyst_qualifications::{
		GeneticAnalystQualificationOwner, GeneticAnalystQualificationsProvider,
	};
	pub use traits_genetic_analyst_services::{
		GeneticAnalystServiceOwner, GeneticAnalystServicesProvider,
	};
	use traits_user_profile::UserProfileProvider;

	#[pallet::config]
	/// Configure the pallet by specifying the parameters and types on which it depends.
	pub trait Config: frame_system::Config + pallet_timestamp::Config {
		/// Because this pallet emits events, it depends on the runtime's definition of an event.
		type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
		type Currency: Currency<Self::AccountId>;
		type GeneticAnalystServices: GeneticAnalystServicesProvider<Self, BalanceOf<Self>>;
		type GeneticAnalystQualifications: GeneticAnalystQualificationsProvider<Self>;
		type GeneticAnalysisOrders: GeneticAnalysisOrderEventEmitter<Self>
			+ GeneticAnalysisOrderStatusUpdater<Self>;
		type EthereumAddress: Clone
			+ Copy
			+ PartialEq
			+ Eq
			+ Encode
			+ EncodeLike
			+ Decode
			+ Default
			+ TypeInfo
			+ sp_std::fmt::Debug;
		type UserProfile: UserProfileProvider<Self, Self::EthereumAddress>;
		type GeneticAnalystWeightInfo: WeightInfo;
		/// Currency type for this pallet.
		type PalletId: Get<PalletId>;
	}

	// ----- This is template code, every pallet needs this ---
	#[pallet::pallet]
	#[pallet::storage_version(STORAGE_VERSION)]
	#[pallet::generate_store(pub(super) trait Store)]
	pub struct Pallet<T>(_);

	#[pallet::hooks]
	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
		fn on_runtime_upgrade() -> Weight {
			migrations::migrate::<T>()
		}
	}
	// --------------------------------------------------------

	// ---- Types ----------------------
	pub type AccountIdOf<T> = <T as frame_system::Config>::AccountId;
	pub type HashOf<T> = <T as frame_system::Config>::Hash;
	pub type MomentOf<T> = <T as pallet_timestamp::Config>::Moment;
	pub type CurrencyOf<T> = <T


helpText = options.helpText;
    }
}

export enum ConfigBaseControlType {
    DROPDOWN = 1,
    NUMBER = 2,
    PERCENTAGE = 3,
    CHECKBOX = 4,
    NONE = 5
}

// export class NumberQuestion extends QuestionBase<string> {
//     controlType: ConfigBaseControlType = ConfigBaseControlType.NUMBER;
//     maskConfig = {
//         mask: createNumberMask({
//             prefix: '',
//             suffix: '',
//             includeThousandsSeparator: true,
//             thousandsSeparatorSymbol: ',',
//             allowDecimal: true,
//             decimalSymbol: '.',
//             decimalLimit: 0,
//             integerLimit: null,
//             requireDecimal: false,
//             allowNegative: false,
//             allowLeadingZeroes: false
//         }),
//         guide: false,
//     };

//     constructor(options: {} = {}) {
//         super(options);
//     }

// }

// export class PercentQuestion extends QuestionBase<string> {
//     controlType: ConfigBaseControlType = ConfigBaseControlType.PERCENTAGE;
//     maskConfig: {};

//     constructor(options: {} = {}) {
//         super(options);
//         this.maskConfig = {
//             mask: createNumberMask({
//                 prefix: '',
//                 suffix: '',
//                 includeThousandsSeparator: true,
//                 thousandsSeparatorSymbol: ',',
//                 allowDecimal: true,
//                 decimalSymbol: '.',
//                 decimalLimit: 0,
//                 integerLimit: null,
//                 requireDecimal: false,
//                 allowNegative: false,
//                 allowLeadingZeroes: false
//             }),
//             guide: false,
//         };
//     }
// }
import _ = require('lodash');

import Deferred from './lib/Deferred';
import commonMistakes from './lib/commonMistakes';
import * as standardSlots from './lib/standardSlots';
import {SlotTypeFunction, SlotTypeItem, ISlotType, IIntentSlot, IIntent} from './lib/nlcInterfaces';

/** Internal utterance matcher. */
interface IUtteranceMatcher {
  intent: IIntent;
  matcher: RegExp;
  mapping: IIntentSlot[];
}

interface IDelay {
  (callback: () => void): number;
}

type SlotMapping = {
  [slotName: string]: any;
}

/** Holds registered natural language commands. */
class NaturalLanguageCommander {
  private slotTypes: { [name: string]: ISlotType } = {};
  private intents: IIntent[] = [];
  private matchers: IUtteranceMatcher[] = [];

  /**
   * @param spellcheckCorpus - An array of words to use as the corpus for the spellchecker.
   */
  constructor () {
    // Add the standard slot types.
    _.forOwn(standardSlots, this.addSlotType);
  }

  /**
   * Add a custom slot type. Bound to this.
   * @param slotType
   */
  public addSlotType = (slotType: ISlotType): void => {
    // Don't allow users to overwrite slot types.
    if (this.slotTypes[slotType.type]) {
      throw new Error(`NLC: Slot Type ${slotType} already exists!`);
    }

    // Get the matcher, so the ts type guards work.
    const matcher = slotType.matcher;

    // Lowercase the slot type matcher.
    if (_.isString(matcher)) {
      slotType.matcher = matcher.toLowerCase();
    } else if (_.isArray(matcher)) {
      slotType.matcher = _.map(matcher, (option: string): string => option.toLowerCase());
    }

    // Save the new type.
    this.slotTypes[slotType.type] = slotType;
  };

  /**
   * Register an intent. Bound to this.
   * @param intent
   */
  public registerIntent = (intent: IIntent): boolean => {
    if


HOPPING_CART. */
    SHOPPING_CART("U+1f6d2"),

    /** ATM. */
    ATM("U+1f3e7"),

    /** PUT_LITTER_IN_ITS_PLACE. */
    PUT_LITTER_IN_ITS_PLACE("U+1f6ae"),

    /** POTABLE_WATER. */
    POTABLE_WATER("U+1f6b0"),

    /** WHEELCHAIR. */
    WHEELCHAIR("U+267f"),

    /** MENS. */
    MENS("U+1f6b9"),

    /** WOMENS. */
    WOMENS("U+1f6ba"),

    /** RESTROOM. */
    RESTROOM("U+1f6bb"),

    /** BABY_SYMBOL. */
    BABY_SYMBOL("U+1f6bc"),

    /** WC. */
    WC("U+1f6be"),

    /** PASSPORT_CONTROL. */
    PASSPORT_CONTROL("U+1f6c2"),

    /** CUSTOMS. */
    CUSTOMS("U+1f6c3"),

    /** BAGGAGE_CLAIM. */
    BAGGAGE_CLAIM("U+1f6c4"),

    /** LEFT_LUGGAGE. */
    LEFT_LUGGAGE("U+1f6c5"),

    /** WARNING. */
    WARNING("U+26a0"),

    /** CHILDREN_CROSSING. */
    CHILDREN_CROSSING("U+1f6b8"),

    /** NO_ENTRY. */
    NO_ENTRY("U+26d4"),

    /** NO_ENTRY_SIGN. */
    NO_ENTRY_SIGN("U+1f6ab"),

    /** NO_BICYCLES. */
    NO_BICYCLES("U+1f6b3"),

    /** NO_SMOKING. */
    NO_SMOKING("U+1f6ad"),

    /** DO_NOT_LITTER. */
    DO_NOT_LITTER("U+1f6af"),

    /** NON_POTABLE_WATER. */
    NON_POTABLE_WATER("U+1f6b1"),

    /** NO_PEDESTRIANS. */
    NO_PEDESTRIANS("U+1f6b7"),

    /** NO_MOBILE_PHONES. */
    NO_MOBILE_PHONES("U+1f4f5"),

    /** UNDERAGE. */
    UNDERAGE("U+1f51e"),

    /** RADIOACTIVE. */
    RADIOACTIVE("U+2622"),

    /** BIOHAZARD. */
    BIOHAZARD("U+2623"),

    /** ARROW_UP. */
    ARROW_UP("U+2b06"),

    /** ARROW_UPPER_RIGHT. */
    ARROW_UPPER_RIGHT("U+2197"),

    /** ARROW_RIGHT. */
    ARROW_RIGHT("U+27a1"),

    /** ARROW_LOWER_RIGHT. */
    ARROW_LOWER_RIGHT("U+2198"),

    /** ARROW_DOWN. */
    ARROW_DOWN("U+2b07"),

    /** ARROW_LOWER_LEFT. */
    ARROW_LOWER_LEFT("U+2199"),

    /** ARROW_LEFT. */
    ARROW_LEFT("U+2b05"),

    /** ARROW_UPPER_LEFT. */
    ARROW_UPPER_LEFT("U+2196"),

    /** ARROW_UP_DOWN. */
    ARROW_UP_DOWN("U+2195"),

    /** LEFT_RIGHT_ARROW. */
    LEFT_RIGHT_ARROW("U+2194"),

    /** LEFTWARDS_ARROW_WITH_HOOK. */
    LEFTWARDS_ARROW_WITH_HOOK("U+21a9"),

    /** ARROW_RIGHT_HOOK. */
    ARROW_RIGHT


来替代此预处理步骤。在这个流中，可用典型的推理执行调用（module.run）使用提供的前 N 个输入动态量化模型（参见更多信息如下），而不需要预先量化模型。这将设置和校准 Vitis-AI DPU，为后面所有输入加速推理。

注意：边缘流与推理中解释的流略有不同，边缘流在前 N 个输入后模型被量化和编译，但推理不会加速，并且它可以移动到边缘设备进行部署。查看下面的 [在 Zynq 上运行](#running-on-zynq-and-vck190) 部分了解更多信息。

``` python
module = graph_executor.GraphModule(lib["default"](tvm.cpu()))

# 前 N 个（默认 = 128）输入用于量化校准，并在 CPU 上执行
# 可以通过设置 “PX_QUANT_SIZE” 来更改此配置（例如，导出 PX_QUANT_SIZE=64）
for i in range(128):
   module.set_input(input_name, inputs[i])
   module.run()
```

用于量化的图像数量默认设置为 128，可以使用 PX_QUANT_SIZE 环境变量更改动态量化的图像数量。例如，在调用编译脚本之前在终端中执行如下命令，将量化校准数据集减少到八幅图像。

``` bash
export PX_QUANT_SIZE=8
```

最后将 TVM 编译器的编译输出存储在磁盘上，方便在目标设备上运行模型。云 DPU（Alveo 和 VCK5000）的情况如下：

``` python
lib_path = "deploy_lib.so"
lib.export_library(lib_path)
```

对于边缘 target（Zynq 和 VCK190），必须为 aarch64 重建。因此首先必须正常导出模块，并同时序列化 Vitis AI runtime 模块（vitis_ai.rtmod）。之后再次加载此 runtime 模块，为 aarch64 重建和导出。

``` python
temp = utils.tempdir()
lib.export_library(temp.relpath("tvm_lib.so"))

# 为 aarch64 target 构建和导出库
tvm_target = tvm.target.arm_cpu('ultra96')
lib_kwargs = {
   'fcompile': contrib.cc.create_shared,
   'cc': "/usr/aarch64-linux-gnu/bin/ld"
}

build_options = {
    'load_runtime_module': export_rt_mod_file
}
with tvm.transform.PassContext(opt_level=3, config={'relay.ext.vitis_ai.options': build_options}):
     lib_edge = relay.build(mod, tvm_target, params=params)

lib_edge.export_library('deploy_lib_edge.so', **lib_kwargs)
```

使用 TVM 和 Vitis AI 编译模型的教程到此结束，有关如何运行已编译的模型，参阅下一节。

## 推理

带有 Vitis AI 流的 TVM 包含编译和推理两个阶段，在编译期间，用户可以选择为当前支持的任何目标设备编译模型。编译模型后生成的文件可用于在推理阶段在目标设备上运行模型。

查


elayFiPPvUlQ34nw4r3snd12SampleFormatfQ34nw4r3snd10OutputMode
UpdateBuffer__Q34nw4r3snd7FxDelayFiPPvUlQ34nw4r3snd12SampleFormatfQ34nw4r3snd10OutputMode:
/* 8037094C 0036C5AC  94 21 FF E0 */	stwu r1, -0x20(r1)
/* 80370950 0036C5B0  7C 08 02 A6 */	mflr r0
/* 80370954 0036C5B4  7C 64 1B 78 */	mr r4, r3
/* 80370958 0036C5B8  90 01 00 24 */	stw r0, 0x24(r1)
/* 8037095C 0036C5BC  38 61 00 08 */	addi r3, r1, 8
/* 80370960 0036C5C0  38 84 00 24 */	addi r4, r4, 0x24
/* 80370964 0036C5C4  80 05 00 00 */	lwz r0, 0(r5)
/* 80370968 0036C5C8  90 01 00 08 */	stw r0, 8(r1)
/* 8037096C 0036C5CC  80 05 00 04 */	lwz r0, 4(r5)
/* 80370970 0036C5D0  90 01 00 0C */	stw r0, 0xc(r1)
/* 80370974 0036C5D4  80 05 00 08 */	lwz r0, 8(r5)
/* 80370978 0036C5D8  90 01 00 10 */	stw r0, 0x10(r1)
/* 8037097C 0036C5DC  4B F2 50 79 */	bl AXFXChorusCallback
/* 80370980 0036C5E0  80 01 00 24 */	lwz r0, 0x24(r1)
/* 80370984 0036C5E4  7C 08 03 A6 */	mtlr r0
/* 80370988 0036C5E8  38 21 00 20 */	addi r1, r1, 0x20
/* 8037098C 0036C5EC  4E 80 00 20 */	blr


"你走得越来越好了。"老太太说。

"还差得远呢。"老张说，但眼睛里闪着光。

冬天第一场雪后，公园里人很少。老张穿着厚厚的棉衣，独自在雪地里走着。他的脚印深深浅浅地印在雪地上，形成一条弯弯曲曲的线。

突然，他跑了起来。虽然只有短短的几步，虽然姿势笨拙得像只企鹅，但他确实跑了起来。雪粒打在脸上，冰凉冰凉的，老张却觉得浑身发热。

他停下来，大口喘着气，白雾从嘴里喷出来。他低头看着自己的腿，它们稳稳地站在雪地里，像两棵老树根。

"经常用腿，健步如飞。"老张对自己说，然后笑了起来。笑声惊起了树上的麻雀，它们扑棱棱地飞向灰蒙蒙的天空。

开春后，老张开始每天早上慢跑。虽然跑得很慢，虽然右腿偶尔还会发麻，但他坚持着。那个穿红衣服的老太太有时会和他一起跑，更多时候是他一个人。

公园里的梧桐树又绿了。老张站在树下，看着自己的影子。影子里的他，腿脚利索，仿佛又回到了年轻时的样子。

"老张！"老伴在远处喊他，"回家吃饭了！"

"来了！"老张应道，然后迈开步子向家跑去。他的步子还不算快，但每一步都踏得坚定有力。

经常用腿，健步如飞。老张终于明白了这句话的意思。生命在于运动，而运动，就是生命本身。#  飞翔的蒲公英与星辰的轨迹
> 没有计划的目标只是一个愿望。 — 安托万·德·圣-埃克苏佩里

![没有计划的目标只是一个愿望。 — 安托万·德·圣-埃克苏佩里](/images/0857a223a9314bc18107ac636fdb46fd.jpg)

在遥远的奥兰小镇，有一个名叫艾米丽的女孩。她从小就有一个梦想，那就是成为一名著名的画家。然而，艾米丽并没有为此制定任何计划，她只是每天幻想着自己画出一幅幅震撼人心的作品，被人们赞颂和收


empty{visibility:hidden!important;width:0}.slds-line-clamp{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;overflow:hidden;text-overflow:ellipsis;white-space:pre-line}.slds-line-clamp_x-small{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;text-overflow:ellipsis;white-space:pre-line}.slds-line-clamp_small{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;overflow:hidden;text-overflow:ellipsis;white-space:pre-line}.slds-line-clamp_medium{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:5;overflow:hidden;text-overflow:ellipsis;white-space:pre-line}.slds-line-clamp_large{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:7;overflow:hidden;text-overflow:ellipsis;white-space:pre-line}/*! HTML5 Boilerplate v5.2.0 | MIT License | https://html5boilerplate.com/ */@media print{*,:after,:before{background:0 0!important;color:#000!important;-webkit-box-shadow:none!important;box-shadow:none!important;text-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}}/*!
 * Bootstrap v3.3.7 (http://getbootstrap.com)
 * Copyright 2011-2016 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type


ribune-unvented-hot-water-cylinders-tribune-twin-coil-c-298_310_322_326.html">Tribune Twin Coil

								Sealed System Vessels

Expansion Vessels

								Telford Unvented Hot Water Cylinders

Tornado Direct Cylinders

Tornado Indirect Cylinders

Tempest Direct Cylinders

Tempest Indirect Cylinders

Tempest Solar Twin Coil Cylinders

Tempest Horizontal Direct Cylinders

Tempest Horizontal Indirect Cylinders

								Thermsaver Unvented Hot Water Cylinders

Thermsaver Indirect Cylinders

Thermsaver Direct Cylinders

Thermsaver Solar Cylinders

<a href="thermsaver-unvented-hot-water-cylinders-thermsaver-horizontal-cylinders-c-298_


tal
																									 * letter iota
																									 */, "\u0399" },
				{ "Κ", "Κ"/* greek capital letter kappa */, "\u039A" },
				{ "Λ", "Λ"/* greek capital letter lambda */, "\u039B" }, { "Μ", "Μ"/*
																									 * greek capital
																									 * letter mu
																									 */, "\u039C" },
				{ "Ν", "Ν"/* greek capital letter nu */, "\u039D" },
				{ "Ξ", "Ξ"/* greek capital letter xi */, "\u039E" }, { "Ο", "Ο"/*
																								 * greek capital letter
																								 * omicron
																								 */, "\u039F" },
				{ "Π", "Π"/* greek capital letter pi */, "\u03A0" },
				{ "Ρ", "Ρ"/* greek capital letter rho */, "\u03A1" }
				/* there is no Sigmaf and no \u03A2 */
				, { "Σ", "Σ"/* greek capital letter sigma */, "\u03A3" },
				{ "Τ", "Τ"/* greek capital letter tau */, "\u03A4" },
				{ "Υ", "Υ"/* greek capital letter upsilon */, "\u03A5" },
				{ "Φ", "Φ"/* greek capital letter phi */, "\u03A6" }, { "Χ", "Χ"/*
																									 * greek capital
																									 * letter chi
																									 */, "\u03A7" },
				{ "Ψ", "Ψ"/* greek capital letter psi */, "\u03A8" }, { "Ω", "Ω"/*
																									 * greek capital
																									 * letter omega
																									 */, "\u03A9" },
				{ "α", "α"/* greek small letter alpha */, "\u03B1" }, { "β", "β"/*
																									 * greek small
																									 * letter beta
																									 */, "\u03B2" },
				{ "γ", "γ"/* greek small letter gamma */, "\u03B3" }, { "δ", "δ"/*
																									 * greek small
																									 * letter delta
																									 */, "\u03B4" },
				{ "ε", "ε"/* greek small letter epsilon */, "\u03B5" },
				{ "ζ", "ζ"/* greek small letter zeta */, "\u03B6" }, { "η", "η"/*
																								 * greek small letter
																								 * eta
																								 */, "\u03B7" },
				{ "θ", "θ"/* greek small letter theta */, "\u03B8" }, { "ι", "ι"/*
																									 * greek small
																									 * letter iota
																									 */, "\u03B9" },
				{ "κ", "κ"/* greek small letter kappa */, "\u03BA" }, { "λ", "λ"/*
																									 * greek small
																									 * letter lambda
																									 */, "\u03BB" },
				{ "μ", "μ"/* greek small letter mu */, "\u03BC" },
				{ "ν", "ν"/* greek small letter nu */, "\u03BD" },
				{ "ξ", "ξ"/* greek small letter xi */, "\u03BE" }, { "ο", "ο"/*
																								 * greek small letter
																								 * omicron
																								 */, "\u03BF" },
				{ "π", "&#


int::from_str(&signature.c).unwrap(),
    s: BigUint::from_str(&signature.s).unwrap(),
  };
  match public_key.verify(message, &signature) {
    Ok(_) => true,
    Err(_) => false,
  }
}

fn parse_public_key(json: String) -> PublicKey {
  #[derive(Debug, Serialize, Deserialize)]
  pub struct PubKey {
    pub e: String,
    pub n: String,
  }
  let public_key: PubKey = serde_json::from_str(&json).unwrap();
  let n = BigUint::from_str(&public_key.n).unwrap();
  let e = BigUint::from_str(&public_key.e).unwrap();
  PublicKey::new(n, e).unwrap()
}

fn parse_key_file<T>(path: &String) -> T
where
  T: serde::de::DeserializeOwned,
{
  let file = match File::open(path) {
    Ok(f) => f,
    Err(e) => panic!("Error occurred opening file: {} - Err: {}", path, e),
  };
  let reader = std::io::BufReader::new(file);
  let public_key: T = serde_json::from_reader(reader).unwrap();
  public_key
}

fn add_failed_vote(table: &mut Table, a: &String, m: &String, c: &String, s: &String) {
  let m = if m.len() <= 30 {
    m.clone()
  } else {
    format!("{}...", &m[..30])
  };
  let c = if c.len() <= 30 {
    c.clone()
  } else {
    format!("{}...", &c[..30])
  };
  let s = if s.len() <= 30 {
    s.clone()
  } else {
    format!("{}...", &s[..30])
  };
  table.add_row(row![format!(
    "common massage: {}\nvotes: {}\nsignature-c: {}\nsignature-s: {}",
    a, m, c, s
  )]);
}
<reponame>Michael-F-Bryan/repo-backup
use crate::git::GitRepo;
use failure::Error;
use futures::Stream;
mod github;
mod gitlab;

pub use self::github::{GitHub, GitHubConfig};
pub use self::gitlab::{GitLab, GitLabConfig};

/// Something which can retrieve the repositories we want to backup.
pub trait Provider {
    fn repositories(&self) -> Box<dyn Stream<Item = GitRepo, Error = Error>>;
}
use dirs::config_dir;
use std::path::PathBuf;
use std::fs::File;
use serde::{
    Serialize,
    Deserialize,
};
use super::api::units::Units;
use super::api::location::LocationPoint;

#[derive(Serialize, Deserialize)]
pub struct WeatherPreferences {
    pub location: String,
    pub lat: f64,
    pub lon: f64,
    pub units: Units,
}

const WEATHER_CONFIG_FILE: &str = "weather.json";

fn config_path() -> PathBuf {
    if let Some(mut dir) = config_dir() {
        dir.push(WEATHER_CONFIG_FILE);
        let path = dir.as_path();

        path.to_path_buf()
    } else {
        panic!("Unable to resolve configuration path")
    }
}

impl WeatherPreferences {
    pub fn from_config() -> Option<WeatherPreferences> {
        let path = config_path();
        if path.exists() {
            let file = File::open(path)
                .expect("Unable to read config file");
            let file_value = serde_json::from_reader(file)
                .expect("File contained incorrect JSON format");
            let config_file: WeatherPreferences = serde


:0 0 0 1px "",0 7px 0 1px "",0 14px 0 1px ""}.top-bar.expanded{background:transparent;height:auto}.top-bar.expanded .title-area{background:#333}.top-bar.expanded .toggle-topbar a{color:#888}.top-bar.expanded .toggle-topbar a span::after{box-shadow:0 0 0 1px #888,0 7px 0 1px #888,0 14px 0 1px #888}@media screen and (-webkit-min-device-pixel-ratio: 0){.top-bar.expanded .top-bar-section .has-dropdown.moved>.dropdown,.top-bar.expanded .top-bar-section .dropdown{clip:initial}.top-bar.expanded .top-bar-section .has-dropdown:not(.moved)>ul{padding:0}}.top-bar-section{left:0;position:relative;width:auto;transition:left 300ms ease-out}.top-bar-section ul{display:block;font-size:16px;height:auto;margin:0;padding:0;width:100%}.top-bar-section .divider,.top-bar-section [role="separator"]{border-top:solid 1px #1a1a1a;clear:both;height:1px;width:100%}.top-bar-section ul li{background:#333}.top-bar-section ul li>a{color:#fff;display:block;font-family:"Helvetica Neue",Helvetica,Roboto,Arial,sans-serif;font-size:0.8125rem;font-weight:normal;padding-left:0.9375rem;padding:12px 0 12px 0.9375rem;text-transform:none;width:100%}.top-bar-section ul li>a.button{font-size:0.8125rem;padding-left:0.9375rem;padding-right:0.9375rem;background-color:#F55B11;border-color:#c94708;color:#fff}.top-bar-section ul li>a.button:hover,.top-bar-section ul li>a.button:focus{background-color:#c94708}.top-bar-section ul li>a.button:hover,.top-bar-section ul li>a.button:focus{color:#fff}.top-bar-section ul li>a.button.secondary{background-color:#e9e9e9;border-color:#bababa;color:#333}.top-bar-section ul li>a.button.secondary:hover,.top-bar-section ul li>a.button.secondary:focus{background-color:#bababa}.top-bar-section ul li>a.button.secondary:hover,.top-bar-section ul li>a.button.secondary:focus{color:#333}.top-bar-section ul li>a.button.success{background-color:#5da423;border-color:#4a831c;color:#fff}.top-bar-section ul li>a.button.success:hover,.top-bar-section ul li>a.button.success:focus{background-color:#4a831c}.top-bar-section ul li>a.button.success:hover,.top-bar-section ul li>a.button.success:focus{color:#fff}.top-bar-section ul li>a.button.alert{background-color:#c60f13;border-color:#9e0c0f;color:#fff}.top-bar-section ul li>a.button.alert:hover,.top-bar-section ul li>a.button.alert:focus{background-color:#9e0c0f}.top-bar-section ul li>a.button.alert:hover,.top-bar-section ul li>a.button.alert:focus{color:#fff}.top-bar-section ul li>a.button.warning{background-color:#f08a24;border-color:#cf6e0e;color:#fff}.top-bar-section ul li>a.button.warning:hover,.top-bar-section ul li>a.button.warning:focus{background-color:#cf6e0e}.top-bar-section ul li>a.button.warning:hover,.top-bar-section ul li>a.button.warning:focus{color:#fff}.top-bar-section ul li>a.button.info{back


 v2 distribution returns a 200`() {
        val riskyPostDistrict = env.configFor(PostDistrictsDistribution, "post_districts_distribution") as Distribution
        assertThat(insecureClient(Request(GET, Uri.of(riskyPostDistrict.endpointUri.toString() + "-v2"))),
            hasStatus(OK).and(hasContentType(ContentType("application/json")))
        )
    }

    @Test
    fun `Risky post districts v2 distribution matches static tier metadata`() {
        val riskyPostDistrict = env.configFor(PostDistrictsDistribution, "post_districts_distribution") as Distribution
        val apiResponse = insecureClient(Request(GET, Uri.of(riskyPostDistrict.endpointUri.toString() + "-v2")))
        val apiContent = Body.auto<Map<String,Any>>().toLens().extract(apiResponse)
        val staticTierMetadata = downloadS3Object(riskyPostDistrict.storeName,"tier-metadata")
        assertThat(apiContent["riskLevels"], equalTo(staticTierMetadata))

    }

    @Test
    fun `Local Messages distribution endpoint returns a 200`() {
        val localMessages = env.configFor(LocalMessagesDistribution,"local_messages_distribution") as Distribution
        assertThat(insecureClient(Request(GET, localMessages.endpointUri)),
            hasStatus(OK).and(hasContentType(ContentType("application/json")))
        )
    }

    @MethodSource("distribution")
    @ParameterizedTest(name = "{arguments}")
    fun `Distribution endpoint returns a 200 and matches resource`(distribution: Distribution) {
        assertThat(insecureClient(Request(GET, distribution.endpointUri)),
            hasStatus(OK).and(distribution.resource.contentMatcher())
        )
    }

    @Suppress("unused")
    companion object {
        @JvmStatic
        private fun distribution(): List<Any> =
            endpoints()
                .filterIsInstance<Distribution>()
                .filterNot { it.resource == DynamicUrl || it.resource == DynamicContent }
    }

    private fun downloadS3Object(bucket: String, key: String): Any {
        val s3 = S3Client.builder().build()
        val s3ObjectResponse = s3.getObject(GetObjectRequest.builder().bucket(bucket).key(key).build())
        val http4kResponse = Response(OK).body(s3ObjectResponse)
        return Body.auto<Map<String,Any>>().toLens().extract(http4kResponse)
    }
}
package uk.nhs.nhsx.pubdash.persistence

import org.junit.jupiter.api.Test
import strikt.api.expectThat
import strikt.assertions.contains
import strikt.assertions.hasSize
import strikt.assertions.isA
import strikt.assertions.isEqualTo
import uk.nhs.nhsx.pubdash.QueryId
import uk.nhs.nhsx.pubdash.QueryResult
import uk.nhs.nhsx.pubdash.fakes.FakeDbClient

class AnalyticsDaoTest {

    private val workspace = "some-workspace"
    private val schema = "analytics_db"
    private val tableAppStore = "analytics_app_store"
    private val tableQrPosters = "analytics_qr_posters"
    private val tableAnalyticsMobile = "analytics_mobile"
    private val tablePostcodeLookup = "analytics_postcode_demographic_geographic_lookup"
    private val queryId = QueryId("some-query-id")

    @Test
    fun `async agnostic dataset sql contains correct workspace and returns queryId`() {
        val dbClient = FakeDbClient(listOf(queryId))
        val dao = AnalyticsDao(workspace, dbClient,tableAnalyticsMobile)

        expectThat(dao.startAgnosticDatasetQueryAsync()).isEqualTo(queryId)
        expectThat(dbClient


60.8,43.8' style='fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' />\n<path class='bond-8 atom-7 atom-9' d='M 50.0,39.7 L 59.0,44.8' style='fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' />\n<path class='bond-9 atom-9 atom-10' d='M 60.8,43.8 L 72.7,39.9' style='fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' />\n<path class='bond-10 atom-10 atom-11' d='M 72.7,39.9 L 74.2,35.5' style='fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' />\n<path class='bond-10 atom-10 atom-11' d='M 74.2,35.5 L 75.6,31.1' style='fill:none;fill-rule:evenodd;stroke:#191919;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' />\n<path class='bond-11 atom-10 atom-12' d='M 72.7,39.9 L 80.1,50.0' style='fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' />\n<path class='bond-11 atom-10 atom-12' d='M 72.0,42.1 L 77.7,50.0' style='fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' />\n<path class='bond-12 atom-12 atom-13' d='M 80.1,50.0 L 84.9,50.0' style='fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' />\n<path class='bond-12 atom-12 atom-13' d='M 84.9,50.0 L 89.7,50.0' style='fill:none;fill-rule:evenodd;stroke:#191919;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' />\n<path class='bond-13 atom-12 atom-14' d='M 80.1,50.0 L 77.5,53.5' style='fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' />\n<path class='bond-13 atom-12 atom-14' d='M 77.5,53.5 L 74.9,57.1' style='fill:none;fill-rule:evenodd;stroke:#0000FF;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' />\n<path class='bond-14 atom-9 atom-15' d='M 60.8,43.8 L 60.8,56.3' style='fill:none;fill-rule:evenodd;strok


/*
 * Copyright (c) 2006-Present, Redis Ltd.
 * All rights reserved.
 *
 * Licensed under your choice of the Redis Source Available License 2.0
 * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the
 * GNU Affero General Public License v3 (AGPLv3).
*/

#include "RG.h"
#include "rg_matrix.h"

GrB_Info RG_Matrix_pending
(
	const RG_Matrix C,              // matrix to query
	bool *pending                   // are there any pending operations
) {
	ASSERT(C       != NULL);
	ASSERT(pending != NULL);

	GrB_Info    info;
	bool        p        =  false;
	bool        res      =  false;
	GrB_Matrix  M        =  RG_MATRIX_M(C);
	GrB_Matrix  DP       =  RG_MATRIX_DELTA_PLUS(C);
	GrB_Matrix  DM       =  RG_MATRIX_DELTA_MINUS(C);

	if(RG_MATRIX_MAINTAIN_TRANSPOSE(C)) {
		info = RG_Matrix_pending(C->transposed, &res);
		ASSERT(info == GrB_SUCCESS);
		if(res == true) {
			*pending = true;
			return GrB_SUCCESS;
		}
	}

	// check if M contains pending changes
	info = GxB_Matrix_Pending(M, &p);
	ASSERT(info == GrB_SUCCESS);
	res |= p;

	// check if delta-plus contains pending changes
	info = GxB_Matrix_Pending(DP, &p);
	ASSERT(info == GrB_SUCCESS);
	res |= p;

	// check if delta-plus contains pending changes
	info = GxB_Matrix_Pending(DM, &p);
	ASSERT(info == GrB_SUCCESS);
	res |= p;

	// set output
	*pending = res;

	return info;
}


    final cheekPaint = Paint()..color = const Color(0xFFFFC1CC);
    final mouthPaint = Paint()
      ..color = Colors.black
      ..style = PaintingStyle.stroke
      ..strokeWidth = 4.0;
    final tearPaint = Paint()..color = Colors.blueAccent;
    final centerX = size.width * 0.5;
    final eyeY = size.height * 0.35;
    final cheekY = size.height * 0.37;
    final mouthY = size.height * 0.44;

    // 볼터치
    canvas.drawOval(
      Rect.fromCenter(center: Offset(size.width * 0.2, cheekY), width: 16, height: 10),
      cheekPaint,
    );
    canvas.drawOval(
      Rect.fromCenter(center: Offset(size.width * 0.8, cheekY), width: 16, height: 10),
      cheekPaint,
    );

    // 눈
    final leftEyeX = size.width * 0.25;
    final rightEyeX = size.width * 0.75;

    // 타원의 가로 세로 길이 설정
    const eyeWidth = 9.5;
    const eyeHeight = 12.5;

    // 왼쪽 눈
    canvas.drawOval(
      Rect.fromCenter(
        center: Offset(leftEyeX, eyeY),
        width: eyeWidth,
        height: eyeHeight,
      ),
      eyePaint,
    );

    // 오른쪽 눈
    canvas.drawOval(
      Rect.fromCenter(
        center: Offset(rightEyeX, eyeY),
        width: eyeWidth,
        height: eyeHeight,
      ),
      eyePaint,
    );

    // 입
    final mouthPath = Path();
    if (level >= 0.7) {
      // 😊 웃는 입
      mouthPath.moveTo(centerX - 10, mouthY);
      mouthPath.quadraticBezierTo(centerX, mouthY + 6, centerX + 10, mouthY);
    } else if (level <= 0.3) {
      // 😢 우는 입
      mouthPath.moveTo(centerX - 12, mouthY + 6);
      mouthPath.quadraticBezierTo(centerX, mouthY - 4, centerX + 12, mouthY + 6);
    } else {
      // 😐 무표정
      mouthPath.moveTo(centerX - 10, mouthY);
      mouthPath.lineTo(centerX + 10, mouthY);
    }
    canvas.drawPath(mouthPath, mouthPaint);

    // 👇 눈물 애니메이션 (level <= 0.3일 때만 표시)
    if (level <= 0.3) {
      final tearDrop = (animation.value % 1.0) * 20;

      final tearLeftX = leftEyeX + 1; // 눈보다 살짝 오른쪽
      final tearLeftY = eyeY + 5 + tearDrop;
      if (tearDrop < 10) {
        canvas.drawOval(
          Rect.fromCenter(center: Offset(tearLeftX, tearLeftY), width: 6, height: 10),
          tearPaint,
        );
      }

      final tearRightProgress = ((animation.value + 0.5) % 0.75);
      final tearRightDrop = tearRightProgress * 20;
      final tearRightX = rightEyeX - 1;
      final tearRightY = eyeY + 5 + tearRightDrop;
      if (tearRightDrop < 10) {
        canvas.drawOval(
          Rect.fromCenter(center: Offset(tearRightX, tearRightY), width: 6, height: 10),
          tearPaint,
        );
      }
    }
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => true;
}

class CuteAlcoholWidget extends StatelessWidget {
  final double level;
  final Animation<double> animation;

  const CuteAlcoholWidget({
    super.key,
    required this.level,
    required this.animation,
  });

  @override
  Widget build(BuildContext context) {
    return CustomPaint(
      size: const Size(240, 280),
      painter: _CuteAlcoholPainter(level, animation),
    );
  }
}

class _CuteAlcoholPainter extends CustomPainter {
  final double level;
  final Animation<double> animation;

  _CuteAlcoholPainter(this.level, this.animation) : super(repaint: animation);

  @override
  void paint(Canvas canvas, Size size) {
    final width = size.width;
    final height = size.height;
    final scaleX = width / 250.0;
    final scaleY = height / 250.0


CL/December/236. Event-02/HTML/scss/_header.scss */
  .header-area .main-header-area {
    padding-top: 0px;
  }
}

@media (min-width: 1200px) and (max-width: 1500px) {
  /* line 16, ../../Arafath/CL/December/236. Event-02/HTML/scss/_header.scss */
  .header-area .main-header-area {
    padding-top: 0px;
  }
}

/* line 32, ../../Arafath/CL/December/236. Event-02/HTML/scss/_header.scss */
.header-area .main-header-area .logo-img {
  text-align: center;
}

@media (max-width: 767px) {
  /* line 32, ../../Arafath/CL/December/236. Event-02/HTML/scss/_header.scss */
  .header-area .main-header-area .logo-img {
    text-align: left;
  }
}

@media (min-width: 768px) and (max-width: 991px) {
  /* line 32, ../../Arafath/CL/December/236. Event-02/HTML/scss/_header.scss */
  .header-area .main-header-area .logo-img {
    text-align: left;
  }
}

@media (min-width: 992px) and (max-width: 1200px) {
  /* line 32, ../../Arafath/CL/December/236. Event-02/HTML/scss/_header.scss */
  .header-area .main-header-area .logo-img {
    text-align: left;
  }
}

@media (max-width: 767px) {
  /* line 46, ../../Arafath/CL/December/236. Event-02/HTML/scss/_header.scss */
  .header-area .main-header-area .logo-img img {
    width: 70px;
  }
}

@media (min-width: 768px) and (max-width: 991px) {
  /* line 46, ../../Arafath/CL/December/236. Event-02/HTML/scss/_header.scss */
  .header-area .main-header-area .logo-img img {
    width: 70px;
  }
}

/* line 58, ../../Arafath/CL/December/236. Event-02/HTML/scss/_header.scss */
.header-area .main-header-area .buy_tkt {
  display: -webkit-box;
  display: -moz-box;
  display: -ms-flexbox;
  display: -webkit-flex;
  display: flex;
  -webkit-align-items: center;
  -moz-align-items: center;
  -ms-align-items: center;
  align-items: center;
  -webkit-justify-content: flex-end;
  -moz-justify-content: flex-end;
  -ms-justify-content: flex-end;
  justify-content: flex-end;
  -ms-flex-pack: flex-end;
}

@media (min-width: 992px) and (max-width: 1200px) {
  /* line 62, ../../Arafath/CL/December/236. Event-02/HTML/scss/_header.scss */
  .header-area .main-header-area .buy_tkt .search_button {
    margin-right: 15px;
  }
}

@media (min-width: 1200px) and (max-width: 1500px) {
  /* line 62, ../../Arafath/CL/December/236. Event-02/HTML/scss/_header.scss */
  .header-area .main-header-area .buy_tkt .search_button {
    margin-right: 15px;
  }
}

/* line 71, ../../Arafath/CL/December/236. Event-02/HTML/scss/_header.scss */
.header-area .m


px 0;border-right:1px solid #202a33}.mce-btn-group .mce-first.mce-last{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.mce-btn-group .mce-btn.mce-flow-layout-item{margin:0}.mce-rtl .mce-btn-group .mce-btn{margin-left:0;margin-right:2px}.mce-rtl .mce-btn-group .mce-first{margin-right:0}.mce-rtl .mce-btn-group:not(:first-child){border-left:none;border-right:1px solid #2f363c;padding-right:4px;margin-right:4px}.mce-checkbox{cursor:pointer}i.mce-i-checkbox{margin:0 3px 0 0;border:1px solid #202a33;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);background-color:#4c5761;background-image:-moz-linear-gradient(top, #515c67, #454f59);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#515c67), to(#454f59));background-image:-webkit-linear-gradient(top, #515c67, #454f59);background-image:-o-linear-gradient(top, #515c67, #454f59);background-image:linear-gradient(to bottom, #515c67, #454f59);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff515c67', endColorstr='#ff454f59', GradientType=0);zoom:1;text-indent:-10em;*font-size:0;*line-height:0;*text-indent:0;overflow:hidden}.mce-checked i.mce-i-checkbox{color:#b5b9bf;font-size:16px;line-height:16px;text-indent:0}.mce-checkbox:focus i.mce-i-checkbox,.mce-checkbox.mce-focus i.mce-i-checkbox{border:1px solid #1e7dad;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(30, 125, 173, 0.85);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(30, 125, 173, 0.85);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(30, 125, 173, 0.85)}.mce-checkbox.mce-disabled .mce-label,.mce-checkbox.mce-disabled i.mce-i-checkbox{color:#6f767e}.mce-checkbox .mce-label{vertical-align:middle}.mce-rtl .mce-checkbox{direction:rtl;text-align:right}.mce-rtl i.mce-i-checkbox{margin:0 0 0 3px}.mce-combobox{position:relative;display:inline-block;*display:inline;*zoom:1;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);*height:


Send_515(
      _id,
      _lib._sel_setThousandSeparator_1,
      value._id,
    );
  }

  bool get localizesFormat {
    return _lib._objc_msgSend_12(_id, _lib._sel_localizesFormat1);
  }

  set localizesFormat(bool value) {
    return _lib._objc_msgSend_483(_id, _lib._sel_setLocalizesFormat_1, value);
  }

  NSString get format {
    final _ret = _lib._objc_msgSend_21(_id, _lib._sel_format1);
    return NSString._(_ret, _lib, retain: true, release: true);
  }

  set format(NSString value) {
    return _lib._objc_msgSend_515(_id, _lib._sel_setFormat_1, value._id);
  }

  NSAttributedString get attributedStringForZero {
    final _ret = _lib._objc_msgSend_583(
      _id,
      _lib._sel_attributedStringForZero1,
    );
    return NSAttributedString._(_ret, _lib, retain: true, release: true);
  }

  set attributedStringForZero(NSAttributedString value) {
    return _lib._objc_msgSend_677(
      _id,
      _lib._sel_setAttributedStringForZero_1,
      value._id,
    );
  }

  NSAttributedString get attributedStringForNil {
    final _ret = _lib._objc_msgSend_583(_id, _lib._sel_attributedStringForNil1);
    return NSAttributedString._(_ret, _lib, retain: true, release: true);
  }

  set attributedStringForNil(NSAttributedString value) {
    return _lib._objc_msgSend_677(
      _id,
      _lib._sel_setAttributedStringForNil_1,
      value._id,
    );
  }

  NSAttributedString get attributedStringForNotANumber {
    final _ret = _lib._objc_msgSend_583(
      _id,
      _lib._sel_attributedStringForNotANumber1,
    );
    return NSAttributedString._(_ret, _lib, retain: true, release: true);
  }

  set attributedStringForNotANumber(NSAttributedString value) {
    return _lib._objc_msgSend_677(
      _id,
      _lib._sel_setAttributedStringForNotANumber_1,
      value._id,
    );
  }

  NSDecimalNumberHandler get roundingBehavior {
    final _ret = _lib._objc_msgSend_678(_id, _lib._sel_roundingBehavior1);
    return NSDecimalNumberHandler._(_ret, _lib, retain: true, release: true);
  }

  set roundingBehavior(NSDecimalNumberHandler value) {
    return _lib._objc_msgSend_680(
      _id,
      _lib._sel_setRoundingBehavior_1,
      value._id,
    );
  }

  @override
  NSNumberFormatter init() {
    final _ret = _lib._objc_msgSend_2(_id, _lib._sel_init1);
    return NSNumberFormatter._(_ret, _lib, retain: true, release: true);
  }

  static NSNumberFormatter new1(PedometerBindings _lib) {
    final _ret = _lib._objc_msgSend_2(
      _lib._class_NSNumberFormatter1,
      _lib._sel_new1,
    );
    return NSNumberFormatter._(_ret, _lib, retain: false, release: true);
  }

  static NSNumberFormatter allocWithZone_(
    PedometerBindings _lib,
    ffi.Pointer<_NSZone> zone,
  ) {
    final _ret = _lib._objc_msgSend_3(
      _lib._class_NSNumberFormatter1,
      _lib._sel_allocWithZone_1,
      zone,
    );
    return NSNumberFormatter._(_ret, _lib, retain: false, release: true);
  }


 是 1，第二次循环 `i` 是 2，加起来是 3，没错。这里的 `$1` 表示 `gdb` 保存着这些中间结果，`$` 后面的编号会自动增长，在命令中可以用 `$1`、`$2`、`$3` 等编号代替相应的值。由于我们本来就知道第一次调用的结果是正确的，再往下跟也没意义了，可以用 `finish` 命令让程序一直运行到从当前函数返回为止：

```bash
(gdb) finish
Run till exit from #0  add_range (low=1, high=10) at main.c:6
0x080483c1 in main () at main.c:14
14		result[0] = add_range(1, 10);
Value returned is $2 = 55
```

返回值是 55，当前正准备执行赋值操作，用 `s` 命令赋值，然后查看 `result` 数组：

```bash
(gdb) s
15		result[1] = add_range(1, 100);
(gdb) p result
$3 = {55, 0, 0, 0, 0, 0, 134513196, 225011984, -1208685768, -1081160480,
...
  -1208623680}
```

第一个值 55 确实赋给了 `result` 数组的第 0 个元素。下面用 `s` 命令进入第二次 `add_range` 调用，进入之后首先查看参数和局部变量：

```bash
(gdb) s
add_range (low=1, high=100) at main.c:6
6		for (i = low; i <= high; i++)
(gdb) bt
#0  add_range (low=1, high=100) at main.c:6
#1  0x080483db in main () at main.c:15
(gdb) i locals
i = 11
sum = 55
```

由于局部变量 `i` 和 `sum` 没初始化，所以具有不确定的值，又由于两次调用是挨着的，`i` 和 `sum` 正好取了上次调用时的值，原来这跟[第 3 章「简单函数」第 4 节「全局变量、局部变量和作用域」例 3.7「验证局部变量存储空间的分配和释放」](1-C-语言入门/ch03-简单函数#e3-7)是一样的道理，只不过我这次举的例子设法让局部变量 `sum` 在第一次调用时初值为 0 了。`i` 的初值不是 0 倒没关系，在 `for` 循环中会赋值为 0 的，但 `sum` 如果初值不是 0，累加得到的结果就错了。好了，我们已经找到错误原因，可以退出 `gdb` 修改源代码了。如果我们不想浪费这次调试机会，可以在 `gdb` 中马上把 `sum` 的初值改为 0 继续运行，看看这一处改了之后还有没有别的 Bug：

```bash
(gdb) set var sum=0
(gdb) finish
Run till exit from #0  add_range (low=1, high=100) at main.c:6
0x080483db in main () at main.c:15
15		result[1] = add_range(1, 100);
Value returned is $4 = 5050
(g


ght (C) 2020-2024. violet-team. Licensed under the Apache-2.0 License.

import 'package:flutter/material.dart';
import 'package:violet/pages/viewer/vertical_viewer_page.dart';

/// Raises an event when two or more fingers touch the screen.
class DoublePointListener extends StatefulWidget {
  final Widget child;
  final BoolCallback onStateChanged;

  const DoublePointListener({
    super.key,
    required this.child,
    required this.onStateChanged,
  });

  @override
  State<DoublePointListener> createState() => __DoublePointListener();
}

class __DoublePointListener extends State<DoublePointListener> {
  /// How many fingers are on the screen?
  int _mpPoints = 0;

  ///
  bool _onStateChanged = false;

  @override
  Widget build(BuildContext context) {
    return Listener(
      onPointerDown: (event) {
        _mpPoints++;
        if (_mpPoints >= 2) {
          if (_onStateChanged) {
            _onStateChanged = false;
            widget.onStateChanged(false);
          }
        }
      },
      onPointerUp: (event) {
        _mpPoints--;
        if (_mpPoints < 1) {
          _onStateChanged = true;
          widget.onStateChanged(true);
        }
      },
      onPointerCancel: (event) {
        _mpPoints = 0;
        _onStateChanged = true;
        widget.onStateChanged(true);
      },
      child: widget.child,
    );
  }
}
// This source code is a part of Project Violet.
// Copyright (C) 2020-2024. violet-team. Licensed under the Apache-2.0 License.

import 'dart:ui';

import 'package:flutter/material.dart';
import 'package:violet/database/user/record.dart';
import 'package:violet/settings/settings.dart';
import 'package:violet/variables.dart';

class ViewerRecordPanel extends StatefulWidget {
  final int articleId;

  const ViewerRecordPanel({super.key, required this.articleId});

  @override
  State<ViewerRecordPanel> createState() => _ViewerRecordPanelState();
}

class _ViewerRecordPanelState extends State<ViewerRecordPanel> {
  String durationToString(int param) {
    if (param < 60) return '${param}s';
    return '${param ~/ 60}m';
  }

  @override
  Widget build(BuildContext context) {
    var records = FutureBuilder(
      future: User.getInstance().then(
        (value) => value.getUserLog().then(
          (value) => value
              .where((e) => e.articleId() == widget.articleId.toString())
              .toList(),
        ),
      ),
      builder: (context, AsyncSnapshot<List<ArticleReadLog>> snapshot) {
        if (!snapshot.hasData) return Container();
        final e = snapshot.data!;
        return ListView.builder(
          physics: const BouncingScrollPhysics(),
          padding: EdgeInsets.zero,
          itemExtent: 50.0,
          itemBuilder: (context, index) {
            if (index == 0) {
              return Container(
                alignment: Alignment.centerLeft,
                padding: const EdgeInsets.symmetric(horizontal: 16),
                child: const Text(
                  'View Record',
                  style: TextStyle(
                    fontSize: 16,
                    fontWeight: FontWeight.bold,
                    color: Colors.white,
                  ),
                ),
              );
            }

            final lastPage = e[index - 1].lastPage() == null
                ? '??'
                : '${e[index - 1].lastPage()} Page';

            var dt = e[index - 1].datetimeStart().toString();

            if (e[index - 1].datetimeEnd() != null) {
              final startDT = DateTime.tryParse(e[index - 1].datetimeStart());
              final end


            // 处理符号链接
            val symbolLink = if (type == "symbolic link" && parts.size > 8) {
                parts.drop(8).joinToString(STAT_SPILT_CHAR)
            } else ""

            // 判断是否为目录
            val isDirectory =
                type == "directory" || permissions.startsWith("d") || isSymbolLinkToDirectory(
                    symbolLink
                )

            // 选择图标
            val icon = when {
                isDirectory -> Res.drawable.icon_folder
                fileName.endsWith(".txt") || fileName.endsWith(".json") ||
                        fileName.endsWith(".xml") || fileName.endsWith(".log") -> Res.drawable.icon_code

                fileName.endsWith(".png") || fileName.endsWith(".jpg") ||
                        fileName.endsWith(".jpeg") || fileName.endsWith(".webp") -> Res.drawable.icon_image

                else -> Res.drawable.icon_file
            }

            val model = AdbFileModel(
                path = "$parentPath/$fileName",
                parentPath = parentPath,
                isDirectory = isDirectory,
                fileName = fileName,
                size = size,
                timeStamp = timestamp.toLong(),
                icon = icon,
                symbolLink = symbolLink,
                permissions = permissions
            )

            return model
        }

        return null
    }

    private fun isSymbolLinkToDirectory(symbolLink: String): Boolean {
        val symbolLinkParts = symbolLink.split(" -> ")
        if (symbolLinkParts.size < 2) return false
        val symbolLinkTarget = symbolLinkParts[1].trim()
        println("symbol link:$symbolLinkTarget")
        // 这里可能是因为symbolLinkTarget包含了隐藏字符或空格,使用trim()清理一下

        if (symbolLinkTarget.trim() == "'/sys/kernel/debug'") {
            return true
        }
        if (symbolLinkTarget == "'/data/user_de/0/com.android.shell/files/bugreports'" || symbolLinkTarget == "'/system/bin/init'") {
            return false
        }
        return symbolLinkTarget.endsWith("/") ||
                symbolLinkTarget.contains("bin") ||
                symbolLinkTarget.contains("etc") ||
                symbolLinkTarget.contains("lib") ||
                symbolLinkTarget.contains("usr") ||
                symbolLinkTarget.contains("var") ||
                symbolLinkTarget.contains("opt") ||
                symbolLinkTarget.contains("home") ||
                symbolLinkTarget.contains("mnt") ||
                symbolLinkTarget.contains("media") ||
                symbolLinkTarget.contains("data") ||
                symbolLinkTarget.contains("kernel") ||
                symbolLinkTarget.contains("system") ||
                symbolLinkTarget.contains("storage")
    }

    /**
     * 判断路径是否包含需要转义的特殊字符
     */
    fun needsEscaping(path: String): Boolean {
        val specialChars = listOf(
            ' ', '\t', '\n', '\r',  // 空白字符
            '(', ')', '[', ']', '{', '}',  // 括号
            '&', '|', ';', '`', '$',  // Shell特殊字符
            '*', '?', '[', ']',  // 通配符
            '"', '\'', '\\',  // 引号和反斜杠
            '<', '>', '|', '^'  // 重定向和管道
        )

        return path.any { it in specialChars }
    }

    /**
     * 对路径进行转义处理
     */
    fun escapePath(path: String): String {
        if (!needsEscaping(path)) {
            return path
        }

        var escapedPath = path

        // 转义反斜杠
        escapedPath = escapedPath.replace("\\", "\\\\")

        // 转义单引号
        escapedPath = escapedPath.replace("'", "'\"'\"'")

        // 转义双引号
        escapedPath = escapedPath.replace("\"", "\\\"")

        // 转义其他特殊字符
        val specialCharMap = mapOf(
            ' ' to "\\ ",
            '\t' to "\\t",
            '\


ne:
                return await ctx.send_help()

            no_box = "```" in raw_check
            if no_box:
                raw_check = escape(raw_check, formatting=True)

            rm_how_to = "Pass `remove` to this command to remove these checks.\n\n"

            for p in pagify(raw_check, page_length=1900, escape_mass_mentions=False):
                if no_box:
                    await ctx.send(rm_how_to + p)
                else:
                    await ctx.send(rm_how_to + box(p, lang="yml"))
                rm_how_to = ""
        elif conditions.lower() == "remove":
            await WardenAPI.remove_check(ctx.guild, module)
            await ctx.tick()
        else:
            try:
                await WardenAPI.set_check(ctx.guild, module, conditions, ctx.author)
            except Exception as e:
                await ctx.send(f"Error setting the checks: {e}")
            else:
                await ctx.send(
                    "Warden checks set. These additional checks will be evaluated "
                    "*after* the module's standard checks (e.g. rank)"
                )


されています。自作のreduceの関数を作成することもできますがこのレッスンでは扱いません。以下にMPIでサポートされている操作を紹介します。

* `MPI_MAX` - 最大値
* `MPI_MIN` - 最小値
* `MPI_SUM` - 合計
* `MPI_PROD` - 乗算
* `MPI_LAND` - 各要素の論理的なAND演算
* `MPI_LOR` - 各要素の論理的なOR演算
* `MPI_BAND` - 各要素のビットAND演算
* `MPI_BOR` - 各要素のビットOR演算
* `MPI_MAXLOC` - 最大値とそれを持つプロセスのランク
* `MPI_MINLOC` - 最小値とそれを持つプロセスのランク

`MPI_Reduce`のイメージを示します。

![MPI_Reduce](../mpi_reduce_1.png)

この例では各プロセスは整数を１つ持ちます。`MPI_Reduce`はプロセス0で呼び出され`MPI_SUM`をreduce演算として使用します。合計された結果がルートプロセスに格納されます。

次は各プロセスが整数を複数持った時のことを考えます。

![MPI_Reduce](../mpi_reduce_2.png)

この例では各プロセスは2つの整数を持ちます。ルートのプロセスではこの2つの数値を一緒にして合計を求めるのではなく、結果を入れる配列のi番目に対して、各プロセスのi番目の数の合計を集約することに注意してください。
つまり、すべての配列の要素を合計して1つの要素にするのではなく、各配列の要素を合計してプロセス0の結果配列のi番目の要素に格納します

`MPI_Reduce` がどのように見えるか理解できたので次のトピックに進みましょう。

## MPI_Reduceを使った平均の計算 - Computing average of numbers with MPI_Reduce
一つ前のレッスンでは`MPI_Scatter`と`MPI_Gather`で数値の平均を求めましたが、`MPI_Reduce`を使うことでより簡単に実装することができます。次に[reduce_avg.c]({{ site.github.code }}/tutorials/mpi-reduce-and-allreduce/code/reduce_avg.c)を示します。

```cpp
float *rand_nums = NULL;
rand_nums = create_rand_nums(num_elements_per_proc);

// 各のプロセスのsumを求める
float local_sum = 0;
int i;
for (i = 0; i < num_elements_per_proc; i++) {
  local_sum += rand_nums[i];
}

// 各のローカル変数の平均を合計と平均を表示する
printf("Local sum for process %d - %f, avg = %f\n",
       world_rank, local_sum, local_sum / num_elements_per_proc);

// 各プロセスで求めたsumをグローバルsumとしてreduceする
float global_sum;
MPI_Reduce(&local_sum, &global_sum, 1, MPI_FLOAT, MPI_SUM, 0,
           MPI_COMM_WORLD);

// 結果の表示
if (world_rank == 0) {
  printf("Total sum = %f, avg = %f\n"


enthyr"] = {47, 47, 0.93017578125, 0.953125, 0.001953125, 0.09375, false, false},
	},
	["interface/covenantrenown/dragonflightmajorfactionscentaur"] = { -- 4726580
		["UI-Centaur-HeaderOrb-Level0"] = {182, 220, 0.6767578125, 0.8544921875, 0.2587890625, 0.4736328125, false, false},
		["UI-Centaur-HeaderOrb"] = {182, 220, 0.7841796875, 0.9619140625, 0.0009765625, 0.2158203125, false, false},
		["UI-Centaur-Highlight-Bottom"] = {798, 228, 0.0009765625, 0.7802734375, 0.5537109375, 0.7763671875, false, false},
		["UI-Centaur-Highlight-Middle"] = {800, 262, 0.0009765625, 0.7822265625, 0.0009765625, 0.2568359375, false, false},
		["UI-Centaur-Highlight-Top"] = {690, 300, 0.0009765625, 0.6748046875, 0.2587890625, 0.5517578125, false, false},
		["UI-Centaur-Reward-Slate"] = {470, 140, 0.0009765625, 0.4599609375, 0.7783203125, 0.9150390625, false, false},
		["UI-Centaur-RewardFrame"] = {128, 128, 0.8564453125, 0.9814453125, 0.2587890625, 0.3837890625, false, false},
		["UI-Centaur-HeaderFill"] = {182, 220, 0.7822265625, 0.9599609375, 0.5537109375, 0.7685546875, false, false},
	},
	["interface/covenantrenown/dragonflightmajorfactionscentaurbackground"] = { -- 4726196
		["Dragonflight-MajorFactions-Centaur-Background"] = {820, 578, 0.0009765625, 0.8017578125, 0.0009765625, 0.5654296875, false, false},
	},
	["interface/covenantrenown/dragonflightmajorfactionsdream"] = { -- 5389682
		["UI-Dream-Highlight-Middle"] = {800, 262, 0.0009765625, 0.7822265625, 0.0009765625, 0.2568359375, false, false},
		["UI-Dream-Highlight-Bottom"] = {798, 228, 0.0009765625, 0.7802734375, 0.5537109375, 0.7763671875, false, false},
		["UI-Dream-Rewardframe"] = {128, 128, 0.8564453125, 0.9814453125, 0.2587890625, 0.3837890625, false, false},
		["UI-Dream-Headerorb-Level0"] = {182, 220, 0.7841796875, 0.9619140625, 0.0009765625, 0.2158203125, false, false},
		["UI-Dream-Headerorb"] = {182, 220, 0.6767578125, 0.8544921875, 0.2587890625, 0.4736328125, false, false},
		["UI-Dream-Reward-Slate"] = {470, 140, 0.0009765625, 0.4599609375, 0.7783203125, 0.9150390625, false, false},
		["UI-Dream-Highlight-Top"] = {690, 300, 0.0009765625, 0.6748046875, 0.2587890625, 0.5517578125, false, false},
		["UI-Dream-Headerfill"] = {182, 220, 0.7822265625, 0.9599609


e_8:
        VLD1.8  {qTmp0, qTmp1}, [ref]!
        SUB     center, center, #32
        VST1.8  {qTmp0}, [fill]!
        VST1.8  {qTmp1}, [fill]!
        B       loop_center
case_7:
        VLD1.8  {dTmp0,dTmp1,dTmp2}, [ref]!
        SUB     center, center, #28
        LDR     tmp2, [ref], #4
        VST1.8  {dTmp0,dTmp1,dTmp2}, [fill]!
        STR     tmp2, [fill],#4
        B       loop_center
case_6:
        VLD1.8  {dTmp0,dTmp1,dTmp2}, [ref]!
        SUB     center, center, #24
        VST1.8  {dTmp0,dTmp1,dTmp2}, [fill]!
        B       loop_center
case_5:
        VLD1.8  {qTmp0}, [ref]!
        SUB     center, center, #20
        LDR     tmp2, [ref], #4
        VST1.8  {qTmp0}, [fill]!
        STR     tmp2, [fill],#4
        B       loop_center
case_4:
        VLD1.8  {qTmp0}, [ref]!
        SUB     center, center, #16
        VST1.8  {qTmp0}, [fill]!
        B       loop_center
case_3:
        VLD1.8  {dTmp0}, [ref]!
        SUB     center, center, #12
        LDR     tmp2, [ref], #4
        VST1.8  dTmp0, [fill]!
        STR     tmp2, [fill],#4
        B       loop_center
case_2:
        LDR      tmp2, [ref],#4
        SUB      center, center, #4
        STR      tmp2, [fill], #4
case_1:
        LDR      tmp2, [ref],#4
        SUB      center, center, #4
        STR      tmp2, [fill], #4

loop_center:
        CMP      center, #0
        BEQ      jump
        LDRB     tmp2, [ref], #1
        SUB      center, center, #1
        STRB     tmp2, [fill], #1
        BNE      loop_center
jump:
        CMP      right,#0
        POPEQ    {r4-r6,pc}
        LDRB     tmp2, [ref,#-1]

loop_right:
        STRB     tmp2, [fill], #1
        SUBS     right, right, #1
        BNE      loop_right

        POP      {r4-r6,pc}

endfunction


min(followtarget.components.locomotor:GetRunSpeed(), TUNING.BOAT.MAX_VELOCITY))
                        or (beaconboat ~= nil and math.min(beaconboat.components.boatphysics:GetVelocity(), TUNING.BOAT.MAX_FORCE_VELOCITY))
                        or 0

    local mindistance = (self.boat.components.hull ~= nil and self.boat.components.hull:GetRadius()) or 1
    if beaconboat and beaconboat.components.hull then
        mindistance = mindistance + beaconboat.components.hull:GetRadius()
    end

    -- If the beacon boat is turning, reduce max speed to prevent too much drifting while turning
    local magnetboatdirection = self.boat.components.boatphysics:GetMoveDirection()
    local magnetdir_x, magnetdir_z = VecUtil_NormalizeNoNaN(magnetboatdirection.x, magnetboatdirection.z)

    local beaconboatdirection = (beaconboat == nil and followtarget.components.locomotor and Vector3(followtarget.Physics:GetVelocity()))
                            or (beaconboat ~= nil and beaconboat.components.boatphysics:GetMoveDirection())
                            or Vector3(0, 0, 0)
    local beacondir_x, beacondir_z = VecUtil_NormalizeNoNaN(beaconboatdirection.x, beaconboatdirection.z)

    local boatspeed = self.boat.components.boatphysics:GetVelocity()

    local turnspeedmodifier = (boatspeed > 0 and beaconspeed > 0 and math.max(VecUtil_Dot(magnetdir_x, magnetdir_z, beacondir_x, beacondir_z), 0)) or 1
    local maxdistance = TUNING.BOAT.BOAT_MAGNET.MAX_DISTANCE / 2

    if distance > mindistance then
        local base = math.pow(TUNING.BOAT.BOAT_MAGNET.MAX_VELOCITY + TUNING.BOAT.BOAT_MAGNET.CATCH_UP_SPEED, 1 / maxdistance)
        local maxspeed = beaconspeed + (math.pow(base, distance - mindistance) - 1) * turnspeedmodifier
        return math.min(maxspeed, TUNING.BOAT.BOAT_MAGNET.MAX_VELOCITY + TUNING.BOAT.BOAT_MAGNET.CATCH_UP_SPEED)
    else
        local maxspeed = beaconspeed * turnspeedmodifier
        return math.min(maxspeed, TUNING.BOAT.BOAT_MAGNET.MAX_VELOCITY)
    end
end

function BoatMagnet:CalcMagnetDirection()
    local followtarget = self:GetFollowTarget()
    if not followtarget then
        return Vector3(0, 0, 0)
    end

    -- Calculate distance between magnet & beacon.
    -- If we're carrying a beacon but walking on a boat, use the boat's position instead
    local boatpos = self.boat:GetPosition()
    local targetpos = followtarget:GetPosition()
    local vel_x, vel_z = VecUtil_NormalizeNoNaN(VecUtil_Sub(targetpos.x, targetpos.z, boatpos.x, boatpos.z))

    local direction = Vector3(vel_x, 0, vel_z)
    local distance = VecUtil_Dist(targetpos.x, targetpos.z, boatpos.x, boatpos.z)

    retu


g the translation per L1Operation. */
		private val levelOneGenerationStats: Array<Statistic> =
			L1Operation.entries.map {
				Statistic(L1_NAIVE_TRANSLATION_TIME, it.name)
			}.toTypedArray()

		/**
		 * Generate the [L2ControlFlowGraph] of [L2Instruction]s for the
		 * [unoptimizedChunk].
		 *
		 * @param initialBlock
		 *   The block to initially entry the default chunk for a call.
		 * @param reenterFromRestartBlock
		 *   The block to reenter to [P_RestartContinuation] an [A_Continuation].
		 * @param loopBlock
		 *   The main loop of the interpreter.
		 * @param reenterFromCallBlock
		 *   The entry point for returning into a reified continuation.
		 * @param reenterFromInterruptBlock
		 *   The entry point for resuming from an interrupt.
		 * @param unreachableBlock
		 *   A basic block that should be dynamically unreachable.
		 * @return
		 *   The [L2ControlFlowGraph] for the default chunk.
		 */
		fun generateDefaultChunkControlFlowGraph(
			initialBlock: L2BasicBlock,
			reenterFromRestartBlock: L2BasicBlock,
			loopBlock: L2BasicBlock,
			reenterFromCallBlock: L2BasicBlock,
			reenterFromInterruptBlock: L2BasicBlock,
			unreachableBlock: L2BasicBlock): L2ControlFlowGraph
		{
			initialBlock.makeIrremovable()
			loopBlock.makeIrremovable()
			reenterFromRestartBlock.makeIrremovable()
			reenterFromCallBlock.makeIrremovable()
			reenterFromInterruptBlock.makeIrremovable()
			unreachableBlock.makeIrremovable()
			val generator = L2Generator(
				UNOPTIMIZED,
				Frame(null, nil, "top frame"),
				"default chunk")

			// 0. First try to run it as a primitive.
			generator.startBlock(initialBlock)
			generator.addInstruction(
				L2_TRY_OPTIONAL_PRIMITIVE)
			generator.jumpTo(reenterFromRestartBlock)
			// Only if the primitive fails should we even consider optimizing the
			// fallback code.

			// 1. Update counter and maybe optimize *before* extracting arguments.
			generator.startBlock(reenterFromRestartBlock)
			generator.addInstruction(
				L2_DECREMENT_COUNTER_AND_REOPTIMIZE_ON_ZERO,
				L2IntImmediateOperand(UNOPTIMIZED.ordinal + 1),
				L2IntImmediateOperand(1))
			// 2. Build registers, get arguments, create locals, capture primitive
			// failure value, if any.
			generator.addInstruction(L2_PREPARE_NEW_FRAME_FOR_L1)
			generator.jumpTo(loopBlock)

			// 3. The main L1 interpreter loop.
			generator.startBlock(loopBlock)
			generator.addInstruction(
				L2_INTERPRET_LEVEL_ONE,
				edgeTo(reenterFromCallBlock),
				edgeTo(reenterFromInterruptBlock))

			// 4,5. If reified, calls return here.
			generator.startBlock(reenterFromCallBlock)
			generator.addInstruction(
				L2_REENTER_L1_CHUNK_FROM_CALL)
			generator.addInstruction(
				L2_JUMP,
				backEdgeTo(loopBlock))

			// 6,7. If reified, interrupts return here.
			generator.startBlock(reenterFromInterruptBlock)
			generator.addInstruction(
				L2_REENTER_L1_CHUNK_FROM_INTERRUPT)
			generator.addInstruction(
				L2_JUMP,
				backEdgeTo(loopBlock))

			// 8. Unreachable.
			generator.startBlock(unreachableBlock)
			generator.addInstruction(L2_UNREACHABLE_CODE)
			return generator.controlFlowGraph
		}

		/** Statistic for number of instructions in L2 translations. */