CloudSim源代码学习——服务代理商(DatacenterBroker)

DatacenterBroker.java文件如下:

(其中,相关语句已经做好标注)

  1 /* 
  2  * Title:        CloudSim Toolkit 
  3  * Description:  CloudSim (Cloud Simulation) Toolkit for Modeling and Simulation of Clouds 
  4  * Licence:      GPL - http://www.gnu.org/copyleft/gpl.html 
  5  * 
  6  * Copyright (c) 2009-2010, The University of Melbourne, Australia 
  7  */
  8 package org.cloudbus.cloudsim;
  9 
 10 import java.util.ArrayList;//Resizable-array implementation of the List interface
 11 import java.util.HashMap;//散列表要解决的一个问题就是散列值的冲突问题,通常是两种方法:链表法和开放地址法。链表法就是将相同hash值的对象组织成一个链表放在hash值对应的槽位  (来源:http://www.yuloo.com/news/1012/527961.html
 12 import java.util.LinkedList;//The class implements the Deque interface, providing first-in-first-out queue operations for add, poll, along with other stack and deque operations
 13 import java.util.List;//An ordered collection (also known as a sequence)
 14 import java.util.Map;//An object that maps keys to values
 15 
 16 import org.cloudbus.cloudsim.core.CloudSim;//This class extends the CloudSimCore to enable network simulation in CloudSim
 17 import org.cloudbus.cloudsim.core.CloudSimTags;//Contains various static command tags that indicate a type of action that needs to be undertaken by CloudSim entities when they receive or send events
 18 import org.cloudbus.cloudsim.core.SimEntity;//This class represents a simulation entity 
 19 import org.cloudbus.cloudsim.core.SimEvent;//This class represents a simulation event which is passed between the entities in the simulation
 20 import org.cloudbus.cloudsim.lists.CloudletList;//CloudletList is a collection of operations on lists of Cloudlets
 21 import org.cloudbus.cloudsim.lists.VmList;//VmList is a collection of operations on lists of VMs
 22 
 23 /**DatacentreBroker类代表一经纪人行使用户角色,隐藏了虚拟机管理,如虚拟机创建,用户任务提交和虚拟机销毁
 24  * DatacentreBroker represents a broker
 25  * acting on behalf of a user. It hides VM management,
 26  * as vm creation, sumbission of cloudlets to this VMs
 27  * and destruction of VMs.
 28  *
 29  * @author        Rodrigo N. Calheiros
 30  * @author        Anton Beloglazov
 31  * @since        CloudSim Toolkit 1.0
 32  */
 33 public class DatacenterBroker extends SimEntity {
 34 
 35     // TODO: remove unnecessary variables移除不必要的变量
 36 
 37     /** The vm list. 虚拟机列表*/
 38     private List<? extends Vm> vmList;
 39 
 40     /** The vms created list. 虚拟机创建列表*/
 41     private List<? extends Vm> vmsCreatedList;
 42 
 43     /** The cloudlet list.云任务列表 */
 44     private List<? extends Cloudlet> cloudletList;
 45 
 46     /** The cloudlet submitted list. 云任务提交列表*/
 47     private List<? extends Cloudlet> cloudletSubmittedList;
 48 
 49     /** The cloudlet received list. 云任务接收列表*/
 50     private List<? extends Cloudlet> cloudletReceivedList;
 51 
 52     /** The cloudlets submitted. 提交的云任务*/
 53     private int cloudletsSubmitted;
 54 
 55     /** The vms requested. 请求的虚拟机*/
 56     private int vmsRequested;
 57 
 58     /** The vms acks.虚拟机确认 */
 59     private int vmsAcks;
 60 
 61     /** The vms destroyed.虚拟机销毁 */
 62     private int vmsDestroyed;
 63 
 64     /** The datacenter ids list. 数据中心ID列表*/
 65     private List<Integer> datacenterIdsList;
 66 
 67     /** The datacenter requested ids list.请求数据中心ID列表 */
 68     private List<Integer> datacenterRequestedIdsList;
 69 
 70     /** The vms to datacenters map. 虚拟机到数据中心映射*/
 71     private Map<Integer, Integer> vmsToDatacentersMap;
 72 
 73     /** The datacenter characteristics list. 数据中心特征列表*/
 74     private Map<Integer, DatacenterCharacteristics> datacenterCharacteristicsList;
 75 
 76 
 77     /**【创建新的数据中心代理对象】
 78      * Created a new DatacenterBroker object.
 79      *
 80      * @param name     name to be associated with this entity (as
 81      * required by Sim_entity class from simjava package)
 82      *
 83      * @throws Exception the exception
 84      *
 85      * @pre name != null
 86      * @post $none
 87      */
 88     public DatacenterBroker(String name) throws Exception {
 89         super(name);
 90 
 91         setVmList(new ArrayList<Vm>());
 92         setVmsCreatedList(new ArrayList<Vm>());
 93         setCloudletList(new ArrayList<Cloudlet>());
 94         setCloudletSubmittedList(new ArrayList<Cloudlet>());
 95         setCloudletReceivedList(new ArrayList<Cloudlet>());
 96 
 97         cloudletsSubmitted=0;//= 与(0)是什么区别
 98         setVmsRequested(0);
 99         setVmsAcks(0);
100         setVmsDestroyed(0);
101 
102         setDatacenterIdsList(new LinkedList<Integer>());
103         setDatacenterRequestedIdsList(new ArrayList<Integer>());
104         setVmsToDatacentersMap(new HashMap<Integer, Integer>());
105         setDatacenterCharacteristicsList(new HashMap<Integer, DatacenterCharacteristics>());
106     }
107 
108     /**【方法 : 发送给代理必须创建的虚拟机列表】
109      * This method is used to send to the broker the list with
110      * virtual machines that must be created.
111      *
112      * @param list the list
113      *
114      * @pre list !=null
115      * @post $none
116      */
117     public void submitVmList(List<? extends Vm> list) {
118         getVmList().addAll(list);
119     }
120 
121     /**【方法 : 发送云任务列表给代理】
122      * This method is used to send to the broker the list of
123      * cloudlets.
124      *
125      * @param list the list
126      *
127      * @pre list !=null
128      * @post $none
129      */
130     public void submitCloudletList(List<? extends Cloudlet> list){
131         getCloudletList().addAll(list);
132     }
133 
134     /**(绑定云任务到指定虚拟机)
135      * Specifies that a given cloudlet must run in a specific virtual machine.
136      *
137      * @param cloudletId ID of the cloudlet being bount to a vm
138      * @param vmId the vm id
139      *
140      * @pre cloudletId > 0
141      * @pre id > 0
142      * @post $none
143      */
144     public void bindCloudletToVm(int cloudletId, int vmId){
145         CloudletList.getById(getCloudletList(), cloudletId).setVmId(vmId);
146     }
147 
148     /**处理可用于代理的事件
149      * Processes events available for this Broker.
150      *
151      * @param ev    a SimEvent object
152      *
153      * @pre ev != null
154      * @post $none
155      */
156     @Override//http://www.javaeye.com/wiki/topic/694939 参考注释
157     public void processEvent(SimEvent ev) {//implements org.cloudbus.cloudsim.core.SimEntity.processEvent
158         //Log.printLine(CloudSim.clock()+"[Broker]: event received:"+ev.getTag());
159         switch (ev.getTag()){
160             // Resource characteristics request资源特征请求
161             case CloudSimTags.RESOURCE_CHARACTERISTICS_REQUEST:
162                 processResourceCharacteristicsRequest(ev);
163                 break;
164             // Resource characteristics answer资源特征应答
165             case CloudSimTags.RESOURCE_CHARACTERISTICS:
166                 processResourceCharacteristics(ev);
167                 break;
168             // VM Creation answer 虚拟机创建应答
169             case CloudSimTags.VM_CREATE_ACK:
170                    processVmCreate(ev);
171                    break;
172             //A finished cloudlet returned 返回一个完成的云任务
173             case CloudSimTags.CLOUDLET_RETURN:
174                 processCloudletReturn(ev);
175                 break;
176             // if the simulation finishes 仿真完成
177             case CloudSimTags.END_OF_SIMULATION:
178                 shutdownEntity();
179                 break;
180             // other unknown tags are processed by this method 处理unknown tags
181             default:
182                 processOtherEvent(ev);
183                 break;
184         }
185     }
186 
187     /**
188      * Process the return of a request for the characteristics of a PowerDatacenter(功率意识数据中心).
189      *
190      * @param ev a SimEvent object
191      *
192      * @pre ev != $null
193      * @post $none
194      */
195     protected void processResourceCharacteristics(SimEvent ev) {
196         DatacenterCharacteristics characteristics = (DatacenterCharacteristics) ev.getData();
197         getDatacenterCharacteristicsList().put(characteristics.getId(), characteristics);
198 
199         if (getDatacenterCharacteristicsList().size() == getDatacenterIdsList().size()) {
200             setDatacenterRequestedIdsList(new ArrayList<Integer>());
201             createVmsInDatacenter(getDatacenterIdsList().get(0));
202         }
203     }
204 
205     /**处理PowerDatacenter特征的请求
206      * Process a request for the characteristics of a PowerDatacenter.
207      *
208      * @param ev a SimEvent object
209      *
210      * @pre ev != $null
211      * @post $none
212      */
213     protected void processResourceCharacteristicsRequest(SimEvent ev) {
214         setDatacenterIdsList(CloudSim.getCloudResourceList());
215         setDatacenterCharacteristicsList(new HashMap<Integer, DatacenterCharacteristics>());
216 
217         Log.printLine(CloudSim.clock()+": "+getName()+ ": Cloud Resource List received with "+getDatacenterIdsList().size()+" resource(s)");
218 
219         for (Integer datacenterId : getDatacenterIdsList()) {
220             sendNow(datacenterId, CloudSimTags.RESOURCE_CHARACTERISTICS, getId());
221         }
222     }
223 
224     /**【请求虚拟机响应应答】
225      * Process the ack received due to a request for VM creation.
226      *
227      * @param ev a SimEvent object
228      *
229      * @pre ev != null
230      * @post $none
231      */
232     protected void processVmCreate(SimEvent ev) {
233         int[] data = (int[]) ev.getData();
234         int datacenterId = data[0];
235         int vmId = data[1];
236         int result = data[2];
237 
238         if (result == CloudSimTags.TRUE) {
239             getVmsToDatacentersMap().put(vmId, datacenterId);
240             getVmsCreatedList().add(VmList.getById(getVmList(), vmId));
241             Log.printLine(CloudSim.clock()+": "+getName()+ ": VM #"+vmId+" has been created in Datacenter #" + datacenterId + ", Host #" + VmList.getById(getVmsCreatedList(), vmId).getHost().getId());
242         } else {
243             Log.printLine(CloudSim.clock()+": "+getName()+ ": Creation of VM #"+vmId+" failed in Datacenter #" + datacenterId);
244         }
245 
246         incrementVmsAcks();
247 
248         if (getVmsCreatedList().size() == getVmList().size() - getVmsDestroyed()) { // all the requested VMs have been created 所有请求虚拟机已创建
249             submitCloudlets();
250         } else {
251             if (getVmsRequested() == getVmsAcks()) { // all the acks received, but some VMs were not created所有响应接受。但一些虚拟机没有创建
252                 // find id of the next datacenter that has not been tried找出下一个数据中心ID
253                 for (int nextDatacenterId : getDatacenterIdsList()) {
254                     if (!getDatacenterRequestedIdsList().contains(nextDatacenterId)) {
255                         createVmsInDatacenter(nextDatacenterId);
256                         return;
257                     }
258                 }
259 
260                 //all datacenters already queried 咨询了所有的数据中心
261                 if (getVmsCreatedList().size() > 0) { //if some vm were created 一些虚拟机已经创建
262                     submitCloudlets();
263                 } else { //no vms created. abort停止
264                     Log.printLine(CloudSim.clock() + ": " + getName() + ": none of the required VMs could be created. Aborting");
265                     finishExecution();
266                 }
267             }
268         }
269     }
270 
271     /**【处理云任务返回事件】
272      * Process a cloudlet return event.
273      *
274      * @param ev a SimEvent object
275      *
276      * @pre ev != $null
277      * @post $none
278      */
279     protected void processCloudletReturn(SimEvent ev) {
280         Cloudlet cloudlet = (Cloudlet) ev.getData();
281         getCloudletReceivedList().add(cloudlet);
282         Log.printLine(CloudSim.clock()+": "+getName()+ ": Cloudlet "+cloudlet.getCloudletId()+" received");
283         cloudletsSubmitted--;
284         if (getCloudletList().size()==0&&cloudletsSubmitted==0) { //all cloudlets executed 所有云任务已执行完
285             Log.printLine(CloudSim.clock()+": "+getName()+ ": All Cloudlets executed. Finishing...");
286             clearDatacenters();
287             finishExecution();
288         } else { //some cloudlets haven't finished yet 一些任务没完成
289             if (getCloudletList().size()>0 && cloudletsSubmitted==0) {
290                 //all the cloudlets sent finished. It means that some bount
291                 //cloudlet is waiting its VM be created云任务发送完毕 
292                 clearDatacenters();
293                 createVmsInDatacenter(0);
294             }
295 
296         }
297     }
298 
299     
300     
301     
302     
303     
304     
305     /**【重写 创建一个新的不同类型的代理】
306      * Overrides this method when making a new and different type of Broker.
307      * This method is called by {@link #body()} for incoming unknown tags.
308      *
309      * @param ev   a SimEvent object
310      *
311      * @pre ev != null
312      * @post $none
313      */
314     protected void processOtherEvent(SimEvent ev){
315         if (ev == null){
316             Log.printLine(getName() + ".processOtherEvent(): " + "Error - an event is null.");
317             return;
318         }
319 
320         Log.printLine(getName() + ".processOtherEvent(): " + "Error - event unknown by this DatacenterBroker.");
321     }
322 
323     /**在数据中心里创建虚拟机
324      * Create the virtual machines in a datacenter.
325      *
326      * @param datacenterId Id of the chosen PowerDatacenter
327      *
328      * @pre $none
329      * @post $none
330      */
331     protected void createVmsInDatacenter(int datacenterId) {
332         // send as much vms as possible for this datacenter before trying the next one
333         int requestedVms = 0;
334         String datacenterName = CloudSim.getEntityName(datacenterId);
335         for (Vm vm : getVmList()) {
336             if (!getVmsToDatacentersMap().containsKey(vm.getId())) {
337                 Log.printLine(CloudSim.clock() + ": " + getName() + ": Trying to Create VM #" + vm.getId() + " in " + datacenterName);
338                 sendNow(datacenterId, CloudSimTags.VM_CREATE_ACK, vm);
339                 requestedVms++;
340             }
341         }
342 
343         getDatacenterRequestedIdsList().add(datacenterId);
344 
345         setVmsRequested(requestedVms);
346         setVmsAcks(0);
347     }
348 
349     /**提交云任务到虚拟机
350      * Submit cloudlets to the created VMs.
351      *
352      * @pre $none
353      * @post $none
354      */
355     protected void submitCloudlets() {
356         int vmIndex = 0;
357         for (Cloudlet cloudlet : getCloudletList()) {
358             Vm vm;
359             if (cloudlet.getVmId() == -1) { //if user didn't bind this cloudlet and it has not been executed yet用户没有绑定云任务
360                 vm = getVmsCreatedList().get(vmIndex);
361             } else { //submit to the specific vm提交给专门的虚拟机
362                 vm = VmList.getById(getVmList(), cloudlet.getVmId());
363                 if (vm == null) { // vm was not created 虚拟机没有创建
364                     Log.printLine(CloudSim.clock()+": "+getName()+ ": Postponing execution of cloudlet "+cloudlet.getCloudletId()+": bount VM not available");
365                     continue;
366                 }
367             }
368 
369             Log.printLine(CloudSim.clock()+": "+getName()+ ": Sending cloudlet "+cloudlet.getCloudletId()+" to VM #"+vm.getId());
370             cloudlet.setVmId(vm.getId());
371             sendNow(getVmsToDatacentersMap().get(vm.getId()), CloudSimTags.CLOUDLET_SUBMIT, cloudlet);
372             cloudletsSubmitted++;
373             vmIndex = (vmIndex + 1) % getVmsCreatedList().size();
374             getCloudletSubmittedList().add(cloudlet);
375         }
376 
377         //从等待列表中除去提交的任务  remove submitted cloudlets from waiting list
378         for (Cloudlet cloudlet : getCloudletSubmittedList()) {
379             getCloudletList().remove(cloudlet);
380         }
381     }
382 
383     /**销毁虚拟机
384      * Destroy the virtual machines running in datacenters.
385      *
386      * @pre $none
387      * @post $none
388      */
389     protected void clearDatacenters() {
390         for (Vm vm : getVmsCreatedList()) {
391             Log.printLine(CloudSim.clock() + ": " + getName() + ": Destroying VM #" + vm.getId());
392             sendNow(getVmsToDatacentersMap().get(vm.getId()), CloudSimTags.VM_DESTROY, vm);
393         }
394 
395         getVmsCreatedList().clear();
396     }
397 
398     /**仿真结束
399      * Send an internal event communicating the end of the simulation.
400      *
401      * @pre $none
402      * @post $none
403      */
404     private void finishExecution() {
405         sendNow(getId(), CloudSimTags.END_OF_SIMULATION);
406     }
407 
408     /* (non-Javadoc)
409      * @see cloudsim.core.SimEntity#shutdownEntity()
410      */
411     @Override
412     public void shutdownEntity() {
413         Log.printLine(getName() + " is shutting down...");
414     }
415 
416     /* (non-Javadoc)
417      * @see cloudsim.core.SimEntity#startEntity()
418      */
419     @Override
420     public void startEntity() {
421         Log.printLine(getName() + " is starting...");
422         schedule(getId(), 0, CloudSimTags.RESOURCE_CHARACTERISTICS_REQUEST);
423     }
424 
425     /**虚拟机列表
426      * Gets the vm list.
427      *
428      * @param <T> the generic type
429      * @return the vm list
430      */
431     @SuppressWarnings("unchecked")
432     public <T extends Vm> List<T> getVmList() {
433         return (List<T>) vmList;
434     }
435 
436     /**设置虚拟机列表
437      * Sets the vm list.
438      *
439      * @param <T> the generic type
440      * @param vmList the new vm list
441      */
442     protected <T extends Vm> void setVmList(List<T> vmList) {
443         this.vmList = vmList;
444     }
445 
446 
447     /**云任务列表
448      * Gets the cloudlet list.
449      *
450      * @param <T> the generic type
451      * @return the cloudlet list
452      */
453     @SuppressWarnings("unchecked")
454     public <T extends Cloudlet> List<T> getCloudletList() {
455         return (List<T>) cloudletList;
456     }
457 
458 
459     /**设置云任务列表
460      * Sets the cloudlet list.
461      *
462      * @param <T> the generic type
463      * @param cloudletList the new cloudlet list
464      */
465     protected <T extends Cloudlet> void setCloudletList(List<T> cloudletList) {
466         this.cloudletList = cloudletList;
467     }
468 
469     /**云任务提交列表
470      * Gets the cloudlet submitted list.
471      *
472      * @param <T> the generic type
473      * @return the cloudlet submitted list
474      */
475     @SuppressWarnings("unchecked")
476     public <T extends Cloudlet> List<T> getCloudletSubmittedList() {
477         return (List<T>) cloudletSubmittedList;
478     }
479 
480 
481     /**设置云任务提交列表
482      * Sets the cloudlet submitted list.
483      *
484      * @param <T> the generic type
485      * @param cloudletSubmittedList the new cloudlet submitted list
486      */
487     protected <T extends Cloudlet> void setCloudletSubmittedList(List<T> cloudletSubmittedList) {
488         this.cloudletSubmittedList = cloudletSubmittedList;
489     }
490 
491     /**云任务接收列表
492      * Gets the cloudlet received list.
493      *
494      * @param <T> the generic type
495      * @return the cloudlet received list
496      */
497     @SuppressWarnings("unchecked")
498     public <T extends Cloudlet> List<T> getCloudletReceivedList() {
499         return (List<T>) cloudletReceivedList;
500     }
501 
502     /**设置云任务接收列表
503      * Sets the cloudlet received list.
504      *
505      * @param <T> the generic type
506      * @param cloudletReceivedList the new cloudlet received list
507      */
508     protected <T extends Cloudlet> void setCloudletReceivedList(List<T> cloudletReceivedList) {
509         this.cloudletReceivedList = cloudletReceivedList;
510     }
511 
512     /**虚拟机列表 ???
513      * Gets the vm list.
514      *
515      * @param <T> the generic type
516      * @return the vm list
517      */
518     @SuppressWarnings("unchecked")
519     public <T extends Vm> List<T> getVmsCreatedList() {
520         return (List<T>) vmsCreatedList;
521     }
522 
523     /**
524      * Sets the vm list.
525      *
526      * @param <T> the generic type
527      * @param vmsCreatedList the vms created list
528      */
529     protected <T extends Vm> void setVmsCreatedList(List<T> vmsCreatedList) {
530         this.vmsCreatedList = vmsCreatedList;
531     }
532 
533     /**虚拟机请求
534      * Gets the vms requested.
535      *
536      * @return the vms requested
537      */
538     protected int getVmsRequested() {
539         return vmsRequested;
540     }
541 
542     /**
543      * Sets the vms requested.
544      *
545      * @param vmsRequested the new vms requested
546      */
547     protected void setVmsRequested(int vmsRequested) {
548         this.vmsRequested = vmsRequested;
549     }
550 
551     /**虚拟机响应
552      * Gets the vms acks.
553      *
554      * @return the vms acks
555      */
556     protected int getVmsAcks() {
557         return vmsAcks;
558     }
559 
560     /**
561      * Sets the vms acks.
562      *
563      * @param vmsAcks the new vms acks
564      */
565     protected void setVmsAcks(int vmsAcks) {
566         this.vmsAcks = vmsAcks;
567     }
568 
569     /**增加虚拟机响应
570      * Increment vms acks.
571      */
572     protected void incrementVmsAcks() {
573         this.vmsAcks++;
574     }
575 
576     /**销毁虚拟机
577      * Gets the vms destroyed.
578      *
579      * @return the vms destroyed
580      */
581     protected int getVmsDestroyed() {
582         return vmsDestroyed;
583     }
584 
585     /**
586      * Sets the vms destroyed.
587      *
588      * @param vmsDestroyed the new vms destroyed
589      */
590     protected void setVmsDestroyed(int vmsDestroyed) {
591         this.vmsDestroyed = vmsDestroyed;
592     }
593 
594     /**数据执行ID
595      * Gets the datacenter ids list.
596      *
597      * @return the datacenter ids list
598      */
599     protected List<Integer> getDatacenterIdsList() {
600         return datacenterIdsList;
601     }
602 
603     /**
604      * Sets the datacenter ids list.
605      *
606      * @param datacenterIdsList the new datacenter ids list
607      */
608     protected void setDatacenterIdsList(List<Integer> datacenterIdsList) {
609         this.datacenterIdsList = datacenterIdsList;
610     }
611 
612     /**虚拟机到数据中心映射
613      * Gets the vms to datacenters map.
614      *
615      * @return the vms to datacenters map
616      */
617     protected Map<Integer, Integer> getVmsToDatacentersMap() {
618         return vmsToDatacentersMap;
619     }
620 
621     /**
622      * Sets the vms to datacenters map.
623      *
624      * @param vmsToDatacentersMap the vms to datacenters map
625      */
626     protected void setVmsToDatacentersMap(Map<Integer, Integer> vmsToDatacentersMap) {
627         this.vmsToDatacentersMap = vmsToDatacentersMap;
628     }
629 
630     /**数据中心特征列表
631      * Gets the datacenter characteristics list.
632      *
633      * @return the datacenter characteristics list
634      */
635     protected Map<Integer, DatacenterCharacteristics> getDatacenterCharacteristicsList() {
636         return datacenterCharacteristicsList;
637     }
638 
639     /**
640      * Sets the datacenter characteristics list.
641      *
642      * @param datacenterCharacteristicsList the datacenter characteristics list
643      */
644     protected void setDatacenterCharacteristicsList(Map<Integer, DatacenterCharacteristics> datacenterCharacteristicsList) {
645         this.datacenterCharacteristicsList = datacenterCharacteristicsList;
646     }
647 
648     /**
649      * Gets the datacenter requested ids list.
650      *
651      * @return the datacenter requested ids list
652      */
653     protected List<Integer> getDatacenterRequestedIdsList() {
654         return datacenterRequestedIdsList;
655     }
656 
657     /**
658      * Sets the datacenter requested ids list.
659      *
660      * @param datacenterRequestedIdsList the new datacenter requested ids list
661      */
662     protected void setDatacenterRequestedIdsList(List<Integer> datacenterRequestedIdsList) {
663         this.datacenterRequestedIdsList = datacenterRequestedIdsList;
664     }
665 
666 }
原文地址:https://www.cnblogs.com/xiaoxiaoweng/p/7412206.html